You are on page 1of 39

DATA STRUCTURES

Data structure:- It is a representation of the logical relationship existing between


individual elements of data. It is a way of organizing all the data items that considers not only the elements stored but also their relationship to each other. Data Structure specifies 4 things:1. Organization of data. 2. Accessing of methods. 3. Degree of associativity. 4. Processing alternatives for information. Structure of input and output data can be used to derive the structure of a program. Data structure affects the design of both structural and functional aspects of the program. Study of data structures involves two complementary goals:1. To identify and develop useful mathematical entities and operations and to determine what classes of problems can be solved by using these entities and operations. 2. To determine representations for abstract entities and to implement the abstract operations on these concrete representations. One important consideration in any implementation is its efficiency. Efficiency is usually measured by 2 factors, Time and Space. Operations on Data structures:1. Create:- This operation results on reserving the memory for the program Execution. This can be done by declaration statement. Creation can be done at compile-time or run-time. 2. Destroy:- It destroys the memory space allocated for specified data structure. malloc() and free() functions of C language are used for create and destroy operations as far as dynamic memory allocation and deallocation is concerned . 3. Selection:- It deals with accessing a particular data within a data structure. 4. Update:- It updates or modifies the data in data structure. 5. Searching:- It finds the presence of the desired data item in the list of data items. 6. Sorting:- This is the process of arranging all data items in a data structure in a particular order. 7. Merging:- This is a process of combining the data items of two different sorted lists into a single sorted list. .

Data Structure

Primitive

Non-primitive

integers

floats

character

pointers

Arrays

Lists

Files

Linear

Non-Linear

Stacks

Queues

Trees

Graphs

STACKS:It is a non-primitive Linear data structure. It is an ordered list in which addition of new data item or deletion of an already existing data item is done at one end. And this end is called the Top of the stack. It is also called as LIFO Data structure. When stack is created, the stack base remains fixed while the stack top changes as elements are added and removed. Representation of stacks can be done in 2 ways:1. Static:- It is an array representation. 2. Dynamic:- It is a linked list representation. Operations on stack:1. Push(s,i); This adds a new data item I on to stack s. The number of data items on stack should not exceed MAXSIZE. 2. i=pop(s); It deletes an item I from stack s. The number of data items should not be deleted beyond 0. 3. i=stacktop(s); It returns the top element of the stack. 4. isempty(s); It returns true if the stack is empty. Otherwise it returns false. 5. isfull(s); It returns true if the stack is full, else it returns false.

Algorithms: Assume that the top value is initialized as top= -1. 1. Push operation:push(int stack[],int maxsize, int top) { int item; if(top==maxsize-1)) { printf(stack is full); return; } else { printf(enter the element to be inserted); scanf(%d,&item); top=top+1; stack[top]=item; } } 2. Pop Operation:pop(int stack[], int top) { int item; if(top==-1) { printf(stack is empty); return; } else { item=stack[top]; top=top-1; } return(item); } Applications of stack:1. Recursion. 2. Keeping track of function calls. 3. Evaluation of Expressions such as infix, prefix, postfix. 4. Reversing the characters. 5. Servicing hardware interrupts. 6. Solving combinatorial problems using backtracking.

Infix, prefix, postfix expressions:An Expression in any programming language is a meaningful combination of operands and operations. Operands may be of int, float, or double. The operators may be arithmetic, logical , relational, or bitwise. There are 3 ways of writing Arithmetic expressions:1.Infix:- Operator is placed between the two operands. Eg: a+b 2.Prefix- Operator is placed before its two operands. Eg: +ab 3.Postfix: Operator is placed after its two operands. Eg: ab+ Order of precedence of operators(Highest to lowest): 1. Exponentiation Right to Left evaluation. 2. * / Left to Right 3. + Left to Right By using parenthesis, we can override the default precedence. The prefix form of a complex expression is not the mirror image of the postfix form. Parenthesis are never needed in prefix and postfix expressions. Converting an infix expression into postfix expression: Steps: 1. Expressions within innermost parentheses must first be converted to postfix, so that they can be treated as single operands. IN this fashion, parentheses can be successfully eliminated until the entire expression is converted. 2. From the given infix expression, if the scanned symbol is an operand, then it is immediately placed on the postfix string. 3. If an operator is scanned, and the stack is found to be empty, then the operator is placed on the stack. 4. If the precedence of the new symbol is greater than the precedence of the symbol on the top of the stack, then the new symbol is pushed on to the stack. 5. If the precedence of the new operator is less than the top of the stack, the operator at the top of the stack is popped and sent to postfix string, and then incoming symbol is compared with the new top symbol, and so on. 6. As the parenthesis changes the order of operations, a) when the ( parentheses is scanned, it is pushed on to the stack. b) When its associated right parentheses is found, all the operators between the two parentheses are placed on the postfix string, because they are to be executed before any operators appearing after the parentheses. Postfix Evaluation: Each operator in a postfix string refers to the previous two operands in the string. Of course, one of these two operands may itself be the result of applying a previous operator. Steps: 1. If an operand is read, it is pushed onto the stack. 2. If an operator is read, then the top two elements of the stack will be the two operands. These two operands are popped, and the indicated operation is performed on them, and the result is pushed back onto the stack, so that it will be available for use as an operand of the next operator.

QUEUES: It is a non-primitive Linear data structure. It is an ordered collection of items from which items are inserted at Rear end, and deleted at front end. It is also called as FIFO data structure, because the first element inserted into the \ Queue is the first element to be removed. Operations:1. insert(q, x); It inserts item x at the rear end of the queue q. 2. x=remove(q); It deletes the element from the front end if the queue q, and sets x to its contents. 3. empty(q): It returns true if the Queue is empty. Otherwise it returns false. Representation of Queue using C can be done in 2 ways:1. Static implementation. 2. Linked list representation. Algorithms: If initially Front=Rear=0 1. insert():- This operation inserts a new item at the rear end of the Queue. Qinsert() { if(rear==maxsize-1) { printf(queue is full); return; } a[rear]=item; rear=rear+1; } 2. delete():- It deletes and returns the data item at the front of the queue. Qdelete() { if(front==0) { printf(Queue is empty); return; } item=q[front]; if(front==rear) front=rear=0; else front=front+1; return; } 3. display(): Displays the elements of the queue.

Qdisplay() { int i; if(front==0) { printf(Queue is empty); return; } else { for(i=front; i<=rear; i++) printf( %d,a[i]); } } Applications of Queue: 1.It is used in Text Editor. 2. It is used in Networking of packets. Drawbacks of Linear Queue:1. Time consuming. 2. There may be a situation where the queue is empty, yet no element can be inserted. To overcome this, 1. One solution is to modify the remove operation so that when an item is deleted, the entire Queue is shifted to the beginning of the array. x=items[0]; for(i=0;i<=rear;i++) items[i]=items[i+1}; rear=rear-1; But the queue, now no longer contains a front field, since the element at position zero of the array is always at the front of the queue. 2. Another solution is to view the array that holds the Queue as a circle rather than as a straight line. i.e. we imagine the first element of the array as immediately following its last element. This is called Circular Queue.

CIRCULAR QUEUES: In Circular Queues, if we reach the end while inserting elements to it, it is possible to insert new elements if the slots at the beginning of the circular queue are empty. Front and Rear values are initialized to the last index of the array, rather than -1 or 0, because the last element of the array is immediately preceded the first one. i.e front=rear=maxsize-1. If the array is full, and an attempt to perform any more insertions causes an overflow. But this is indicated by the fact that front=rear, which is precisely the indication for empty queue. It seems that there is no way to distinguish between the empty Queue and the full Queue under this implementation.

One solution is to sacrifice one element of the array and to allow a queue to grow only as large as one less than the size of the array. Thus if an array of 100 elements is declared as Queue, the queue may contain up to 99 elements. An attempt to insert an 100th element into the Queue causes an overflow. The test for Queue full in cqinsert() occurs after rear has been adjusted whereas test for the Queue Empty in cqdelete() occurs immediately upon entering the routine, before front is updated. cqinsert() { if((rear+1)%size==front) printf(Queue is Full); else { cq[(rear+1)%size]=k; rear=(rear+1)%size; } } cqdelete() { if(front==rear) printf( Queue is empty); else { front=(front+1)%size; return (cq[front]); } }

PRIORITY QUEUES: It is a collection of elements such that each element has been assigned a priority, and such that the order in which elements are added or deleted and processed comes from the following rules: 1. An element of higher priority is processed before any element of lower priority. 2. Two elements with the same priority are processed according to the order in which they are added to the queue. The single-priority Queue can be visualized as 3 separate queues, each exhibiting a strictly FIFO behavior. Elements in the second queue are removed only when the first queue is empty, and elements from the third queue are removed only when the first and second queues are empty. When an elements are inserted they are always added at the end of one of the queues s determined by the priority. Alternatively, if a single sequential storage is used for the priority queue, then insertion may mean that the new element must be inserted in the middle of the structure. 2 types of Priority Queues:1. Ascending priority Queue:_ It is a collection of items into which items can be inserted arbitrarily, and from which only the smallest item can be removed.

2. Descending priority Queue:- It is a collection of items into which items can be inserted arbitrarily, and from which only the largest item can be removed.

DEQUEUES: It is also a homogenous list of elements in which insertion and deletion operations are performed from both the ends. i.e. we can insert elements from the rear end and from the front end. Similarly the deletion can be made either from the front end, or from the rear end. Hence it is called Double-Ended Queue or Deque. Since both insertions and deletions are performed from either end, it is necessary to design algorithms to the following 4 operations. 1. insertion of an element at the rear end of the queue. dqinsert_rear() { if(rear==(Maxsize-1)) { printf(dequeue is full); return; } rear=rear+1; dq[rear]=item; } 2. Deletion of an element from the front end of the queue. Dqdelete_front() { if(front==rear) { printf(Dequeue is empty); return; } front=front+1; item=dq[front]; } 3. Insertion of an element at the front end of the queue. Dqinsert_front() { if(front==0) { printf(Dequeue is full); return; } front=front-1; dq[front]=item;

} 4. Deletion of an element from the rear end of the queue. Dqdelete_rear() { if(front==rear) { printf(Deque is empty); return; } rear=rear-1; item=dq[rear]; } 5. Algorithm to display the contents of Dequeue. Dqdisplay() { if(front<=rear) { printf(status of Queue); for(i=front; i<=rear; i++) printf(%d,dq[i]); } else printf(Queue is empty); } Dequeues are classified into two types:- They are based on the restrictions to perform the insertions or deletions only at one end. 1. Input-Restricted Queue:- Insertion can be done only from any one of the end. whereas deletion can be done from both the ends. 2. Output-restricted Queue:- Deletion can be done only from any one of the end, whereas insertion can be done from both the ends.

UNIT- 4 1. Write a C program to convert the postfix string to infix string? 2. Write a C program to convert the infix string to prefix string? 3. Write a C program to convert the prefix string to infix string? 4. Write an algorithm to insert the elements into circular Queue and delete the elements from the circular queue and display the elements of the circular queue? 5. Distinguish between stack and Queue? Write a C program for adding and deleting items from the stack? 6. What are the applications of stacks and Queues? briefly explain? 7. Write a C program that uses stacks to check for matching left and right parenthesis, left and right braces, and left and right brackets, in a string of characters? 8. Declare a queue of integers? Write a function (a) to insert an element into queue (b) to delete an element from queue 9. What is Deque? What is input restricted deque and output restricted deque? 10. What is priority Queue? In what way can you represent it?

DYNAMIC MEMORY ALLOCATION C Language requires the number of elements in an array to be specified at compile time. But our initial judgment of size, may cause failure of the program or wastage of memory space. The process of allocating memory at runtime is known as dynamic memory allocation. Although C does not inherently have this facility, there are 4 library routines known as memory management functions that can be used for allocating and freeing memory during program execution.

10

1. malloc():- It allocates requested size of bytes and returns a pointer to the first
byte of the allocated space. ptr=(cast type *) malloc(byte-size); 2. calloc(): It allocates space for am array of elements,initializes to 0, and returns a pointer to the memory. ptr=(cast type *)calloc(n,elem-size); 3. free():- It frees previously allocated space. free(ptr); 4. realloc():- It modifies the size of previously allocated space. ptr=realloc(ptr,newsize);

Memory allocation process:-

Local Variables Free Memory Global variables C programs Instructions


Program instructions and global and static variables are stored in a region known as permanent storage area. Local variables are stored in an area called stack. The memory space that is allocated between these two regions is available for dynamic allocation during execution of the program. This free memory region is called heap. The size of heap keeps changing when program is executed due to creation and destroying of variables that are local to functions and blocks.

LINKED LISTS In sequential or array representation, it is necessary to declare in advance the amount of memory to be utilized. This is done by declaring the maximum size of an array. So if the memory is allocated before the execution of a program, it is fixed and cannot be changed. The alternate strategy is to allocate memory only when it is required. For this, a data structure called Linked lists is used. It provides a more flexible storage system and it does not require the use of arrays. Linked List: It is a non sequential collection of data items.

11

The data items in linked list are not in consecutive memory locations. But they may be anywhere in memory. However accessing of these items, is easier as each data item contained within itself the address of next data item. Advantages:1. Linked Lists are dynamic data structures. i.e they can grow or shrink during the execution of a program. 2. Efficient memory utilization:- Here memory is not pre-allocated. Memory is allocated whenever it is required. And it is de-allocated when it is no longer needed. 3. They provide flexibility in allowing the items to be arranged efficiently. 4. Insertions and deletions are easier and efficient. Disadvantages:1. More Memory: If the number of nodes are more, then more space is needed. 2. Access to an arbitrary data items is little bit cumbersome and also time consuming.

Components of a Linked List:A linked list is a non sequential collection of data items called nodes. These nodes are structures containing two fields. 1. data field:- It contains an actual value to be stored. 2. next field:- It contains the address of a next data item. The address used to access a particular node is known as pointer. So the elements in the linked list are ordered not by their physical placement in memory, but by their logical links stored as part of the data within the node itself. So the logical and physical ordering of data items in a linked list need not be the same But in sequential representation, these ordering are the same. Null Pointer:- The next field of the last node is zero, rather than a valid address. External pointer:- It is a pointer to the very first node in the linked list. It enables us to access the entire linked list. Empty List:- If the nodes are not present in the linked list, then it is called as an empty linked list, or empty list, or Null list. Header node:- Sometimes it is desirable to keep an extra node at the front of a list. Such a node does not represent an item in the list and is called header node or list header

Representation of Linked List:physical view:-

Data Next

Logical view:-

struct node

12

{ int data; struct node *next; }; Types of Linked Lists:1. Single Linked List. 2. Double Linked list. 3. Circular Linked list. 4. Circular doubly linked list. 1. Single Linked List:- It is the one in which all nodes are linked together in some sequential manner. Hence it is also called as linear linked list. We can create a linked list using either iteration or recursion. Drawback is that we cannot access the predecessor from the current node. This can be overcome by Double linked list. Creation of list:- We consider head as an external pointer which helps in creating accessing other nodes in the linked list. struct node *head; head=(struct node *)malloc(sizeof(struct node)); if we want to create one more node, we have, head->next=(struct node *)malloc( sizeof (struct node)); Insertion:begin if (the list is empty ) or ( the new node comes before the head node), then insert the new node as the head node, else if( the new node comes after the last node), then insert the new node as the end of the node else insert the new node in the body of the list/ end. Algorithm for placing the new node at the beginning of the linked list:1. Obtain space for new node. 2. Assign data to the item field of the new node. 3. Set the next field of the new node to point to the start of the list 4. Change the head pointer to point to the new node. Algorithm for inserting the new node X between two existing nodes say N1 & N2: 1. Set space for new node. 2. Assign values to the data field of X. 3. Set the next field of X to point to node N2. 4. Set next field of N1 to point to X. Algorithm for inserting the new node at the end of the linked list:1. If the list is empty, then create the new node. and

13

2. If the list is not empty, then go to the last node, and then insert the new node after the last node. Deletion:In order to delete a node from the list, it is necessary to search for location of deletion. The steps involved in deletion are, 1. If the linked list is empty, then display deletion is not possible. 2. Deleting first node:-If the node to be deleted is the first node, pointed to by head pointer, then set the pointer head to the second node in the linked list. Then free the first node. 3. Deleting last node:- If the liked list is not empty, then go on traversing the list till the last but one node. Set the link field of the last but one node to NULL. Then free the last node. 4. Deleting the node from the specified position:- i.e. for deleting the node between node A and node B:If the linked list is not empty, then make the linked field of node A to point to node B. Free the node between node A and node B. Note: If a list is traversed, the external pointer to the list must be preserved to be able to reference the list again. Advantages of Single Linked list: Accessibility of a node in the forward direction is easier. Insertion and deletion of nodes are easier. Disadvantages:Accessing the preceding node of a current node is not possible as there is no backward traversal. Accessing a node is time consuming. 2. Circular Linked Lists:Given a pointer p to a node in a linear list, we cannot reach any of the nodes that precede node(p). So a small change is made to the structure of a linear list, so that the next field of the last node contains a pointer back to the first node rather than the NULL pointer. Such a list is called Circular list. Circular linked list has no end and no beginning.

Insertion:1. Inserting a node at the beginning of the list:1. Allocate the memory for the new node. 2. Assign the values to the data field of the new node. 3. If the list is empty, then set head=last=new node. 4. Otherwise make the next field of the new node to point to the head node. Also make the next field of the last node to point to the new node. 2. Inserting the node at the end of the list:1. Allocate the memory for the new node. 2. Assign the values to the data field of the new node. 3. If the list is empty, then set head=last=new node.

14

4. Otherwise make the next field of the last node to point to the new node. Also make the next field of the last node to point to the new node.

Deletion:1. Deleting a node from the beginning:- (i.e node pointing to head).
1. If the list is empty, then print List is empty and no deletion 2. if the node pointing to the head node is equal to the last node, then set head=last=NULL. 3. Otherwise make the temporary pointer temp to point to the first node, and make the head pointer to point to the next node in the list Then set the next field of the last node to point to wherever the first Node is pointing to. Finally free the node that is pointing to temp. 2. Deleting a node from the end of the list:1. If the list is empty, then print List is empty and no deletion 2. if the node pointing to the head node is equal to the last node, then set head=last=NULL. 3. Otherwise go on traversing till the last but one node,and set its next field to point back to the first node. Then free the last node. Advantages: A circular list can be used to represent a stack or queue. Nodes can be accessed easily. Deletion of a node is easier. Disadvantages: It may enter in to an infinite loop. head node is required to indicate the Start or End of the circular linked list. backward traversing is not possible.

3. Double linked lists:One of the most striking disadvantage of Single and Circular linked list is the inability to traverse the list in backward direction. And the most appropriate data structure for traversing the list in backward direction is Double linked list. It is the one in which all nodes are linked together by multiple number of links which help in accessing both successor and predecessor from the given node position. So it provides bidirectional traversing. Each node has three fields:-

prev

data

next

data field: It contains the data of a particular node.

15

prev field: It points to the predecessor node. next field: It points to the successor node. Insertion:1. Inserting node at the beginning of double linked list: 1. Allocate the memory to the new node. 2. Assign the value to the data field. 3. Assign prev and next fields to NULL. 4. Make the next field of new node to point to the head node of the list. And make the prev field of the node to point to the new node. 5.Finally reset the head pointer.i.e. make it point to the new node which has inserted at the beginning. 2. Inserting the node at the end of the double linked list 1. Allocate the memory to the new node. 2. Assign the value to the data field. 3. Assign prev and next fields to NULL. : 4. If the list is not empty, then traverse the list till the last node and make the next link of the last node to point to the new node and prev link of the new node to point to the last node. Deletion:1. Deleting a node from the beginning:- (i.e node pointing to head). 1. If the list is empty, then print List is empty and no deletion 2. Otherwise make the head pointer to point to the second node and if he second node is not null, then make its prev field to point to NULL. 2.Deleting a node from the end of the list:1.If the list is empty, then print List is empty and no deletion 2.Otherwise traverse the list till the last but one node and make the next field of the last but one node to NULL. 3.Free the last node. Advantages: Insertion and deletion are simple as compared to other Linked lists. Efficient utilization of memory. Bidirectional traversal helps in efficient and easy accessibility of nodes. Disadvantage: It uses two pointers.

Circular double Linked List:It is the one which has both the successor pointer and predecessor pointer in Circular manner. Consider the situation of an empty list. This situation can be dispensed with by never allowing a list to be empty. It can be accomplished by providing a special node called head node that always remains in the list. It is the only node that can be present in an empty list. This head node is useful in realizing a some degree of symmetry in the linked structure by making the list circular. Insertion:-

16

1.Inserting node at the beginning of double linked list: 1.Allocate the memory to the new node. 2.Assign the value to the data field. 3.Assign next field of the head node to point to the new node and prev field of the new node to point to the head node. And similarly make the next field of the new node, to the node immediately appearing after the head node and the prev field of this node pointing back to the new node. 2. Inserting the node at the end of the double linked list 1. Allocate the memory to the new node. 2. Assign the value to the data field. 3. Make the prev field of head node to point to new node and next field of rightmost node to point to the new node. And similarly make the next field of the new node to point to the head node. Deletion:1.Deleting a node from the beginning:1. If the next field of head node is pointing to itself, then print the message List is Empty . 2. Make the next field of head node to point to the second node and the prev field of the second node to point to the head node. 3. Free the first node. 2. Deleting the node from the end: 1. If the next field of the head node is pointing to itself, then print empty list. 2. Make the next field of the last but one node to point to the head node and similarly the prev field of the head node to point to the last but one node in the list. 3. Free the last node.

Applications of linked lists:The addition of long positive integers is possible using circular lists. Implementation of stacks and queues can be done using linked lists. 1.Linked Stacks:-A stack is a data structure in which all insertions and deletions are performed at one end called Top. Using single linked list. Inserting a new element at the front is equivalent to the pushing a new element onto the stack at the top position. And similarly, deleting an element from the beginning of linked list is similar to popping an element from the top of the stack. 2. Linked Queues:- A queue is a data structure in which all the insertions are performed at one end called rear, and all the deletions are performed at the other end called front. In a linked queue, the insertion of a new node is done at the end of linked l list. And the deletion is performed from the beginning of the linked list. Addition of two polynomials:steps: 1. Read the number of terms in P. 2. Read the coefficient and exponents of first polynomial. 3. Read the number of terms in Q. 4. Read the coefficients and exponents of second polynomial .

17

5. Set the temporary pointers p and q to traverse the two polynomials respectively. 6. Compare the exponents of two polynomials starting rom the first node. a. If both exponents are equal, then add the coefficients and store it in the resultant linked list. b. If the exponent of current item in the first polynomial p is less than the exponent of the current item in the second polynomial, then the current item of the second polynomial is added to the resultant linked list. And move the pointer q to point to the next node in the second polynomialQ. c. If the exponent of current item in the first polynomial p is greater than the exponent of the current item in the second polynomial, then the current item of the first polynomial is added to the resultant linked list. And move the pointer p to point to the next node in the first polynomial P. d. Append the remaining nodes of either of the polynomials to the resultant linked list.

18

TREES Trees:They are non-primitive nonlinear data structure. They are very flexible, versatile. They are powerful data structures that can be used to represent data items possessing hierarchial relationship among them. Natural trees grow upwards from the ground into air . But tree data structure grows downwards from top to bottom. Tree terminology: Root: It is a specially designated data item in a tree. It is the first in the hierarchal arrangement of data items. Node: Each data item in a tree is called a node. It specifies the data information and links to other data items. Degree of a node: It is the number of sub trees of a node in a given tree. Degree of a tree:- It is the maximum degree of the nodes in a given tree. Terminal or leaf node:- A node with degree zero. Non-Terminal or non-leaf node:- Any node except the root node whose degree is not zero is called non-leaf node. Siblings:- The children nodes of a given parent node are called siblings. Level:- The entire structure is leveled in such a way that the root node is always At level zero. In General, if a node is at level n, then its children will be at level n+1. Edge:- It is a connecting line of two edges. Path:- It is a sequence of consecutive edges from the source node to the destination node. Depth:- It is the maximum level of any node in a given tree.

19

Forest:- It is a set of disjoint trees. In a given tree, if we remove its root node, then it becomes forest. Binary Tree: Although the nodes in a general tree, may contain any number of pointers to the other tree nodes, a large number of data structures have at most two pointers to the other tree nodes. This type of a tree is called a Binary Tree. The maximum degree of any node is at most two. I.e. there may be a zero node, or one node or two degree node. For any node n, the father of a node having index n, is at floor((n-1)/2). The left child of node numbered n is at index (2n+1). The right child of node numbered n is at index (2n+2). If the left child at index n is given, then its right sibling is at (n+1). If the right child at index n is given, then its left sibling is at (n-1). Strictly Binary Tree: If every non-terminal node in a binary tree consist of non-empty left sub-tree and right sub-tree , then such a tree is called SBT. Complete Binary Tree: A binary tree with n nodes, and of depth d is a strictly binary tree, all of whose terminal nodes are at level d. If there are m nodes at level i, then a binary tree contains at most 2m nodes at level i+1. A binary tree has exactly one node at the root level, and has at most 2i nodes at level i. The maximum number of nodes in a binary tree of depth d is 2d-, where d>=1. The total number of nodes in Complete binary tree with n terminal nodes is 2(n-1). A binary tree with n nodes has exactly (n+1) null branches. Left Skewed Binary tree:-The tree having only left sub tree. Right Skewed Binary Tree:- The tree having only right sub tree. Binary Tree(Linked list )representation:Struct btree { struct btree *lchild; int data; struct btree *rchild; }; Note: Array representation is more ideal for Complete Binary tree. But this is not suitable, for others as it results in unnecessary wastage of memory space. Disadvantages of array representation of Binary Trees: 1. Not suitable for normal binary trees. It is only ideal for complete bunary trees. 2. More memory is unnecessarily wasted. 3. Insertion and deletion at the middle of the tree is cumbersome. These problems can be solved by linked list representation for Binary Trees, Traversal of a Binary Tree: It is to visit each node in the tree exactly once. Binary tree traversal is useful in many applications.

20

The order in which nodes of a linear list are visited is clearly from the first node to the last node. However, there is no such natural linear order for the nodes of a tree. The methods differ primarily in the order in which they visit the nodes. There are 3 popular methods of binary tree traversal. They are: 1. Pre-order traversal. 2. In-order traversal. 3. Post-order traversal.

PreOrder Traversal:To traverse a non-empty binary tree in preorder, we perform the following 3 operations. 1. Visit the root. 2. Traverse the left sub tree in preorder. 3. Traverse the right sub tree in preorder. Recursive Algorithm:rpreorder(T) Step1. if(T=NULL) then Print tree empty Stop. Step2: print data(T). Step3: if( lchild(T) <> NULL) then Call rpreorder(lchild(T)) Step4: if(rchild(T) <> NULL) then Call rpreorder(rchild(T)) Step5: Halt Iterative Algorithm: ipreorder(T) step1: if(T= NULL) then print Empty Tree Return Otherwise Top 0 S push(S, Top, T) //S is a stack Step2: [Process each stacked Branch Address] Repeat step 3 while TOP > 0 step 3: [Get stored address and branch left ] P POP(S,TOP) Repeat while P<>NULL Write(DATA(P)) If RPTR(P) <> NULL then Call PUSH(S,TOP,RPTR(P))(store address of nonempty right subtree) P LPTR(P) (Branch left) step 4: [Finished] Return

21

Inorder Traversal:To traverse a non-empty binary tree in inorder, we perform the following 3 operations. 1. Traverse the left sub tree in inorder. 2. Visit the root. 3. Traverse the right sub tree in inorder. Recursive Algorithm:rinorder(T) Step1. if(T=NULL) then Print tree empty Stop. Step2: if( lchild(T) <> NULL) then Call rinorder(lchild(T)) Step3: print data(T). Step4: if(rchild(T) <> NULL) then Call rinorder(rchild(T)) Step5: Halt Iterative Algorithm: iinorder(T) step1: if(T= NULL) then print Empty Tree Stop. Step2: P T Step3: Repeat steps 4 thru 5 while P<>NULL Step4: S Push(S,P) Step5: P lchild(P) Step6: if(S<> NULL) then P pop(S) print data(P) P rchild(P) Step7: if((P<>NULL) or (S<> NULL)) then Go to step 3. Step8: Halt PostOrder Traversal:To traverse a non-empty binary tree in preorder, we perform the following 3 operations. 1. Traverse the left sub tree in postorder. 2. Traverse the right sub tree in postorder. 3. Visit the root. Recursive Algorithm:rpostorder(T) Step1. if(T=NULL) then Print tree empty Stop.

22

Step2: if( lchild(T) <> NULL) then Call rpostorder(lchild(T)) Step3: if( rchild(T) <> NULL) then Call rpostorder( rchild(T)) Step4: print data(T). Step5: Halt Iterative Algorithm: ipostorder(T) step1: if(T= NULL) then print Empty Tree Stop. Return else PT Top 0 Step2: [ Traverse in postorder] repeat thru step5 while true step 3: [Descend left] Repeat while P<> NULL Call PUSH(S, Top,P) P LPTR(P) step4: [Process a node whose left and right, sub trees have been traversed]. Repeat while S[TOP] <0 P POP(S,TOP) write(DATA(P)). IF TOP = 0 then (have all nodes been traversed?) Return step5: [Branch right and then mark node from which we branched] P RPTR(S[TOP]) S[TOP] -S[TOP] Binary Search Tree:A Binary tree that has the property that all the elements in the left sub tree of a node n, are less than the contents of n, and all elements in right sub tree of n, are greater than or equal to the contents of n, is called Binary Search Tree. Creation of Binary Search Tree:-

Algorithm for creating a Binary Search tree: Createtree(S,X) Step1: getnode(q) Step2: left(q) right(q) NULL Step3: data(q) X Step4: if(S= NULL) then Return (q) Step5: P S Step6: parent NULL Step7: repeat steps 8,9 while P <> NULL Step8: parent P 23

Step9: if( X < data(P) ) then P left(P) otherwise P right(P) Step10: if( data(parent) > X) then Left(parent) q Otherwise Right(parent) q Step11: return Step12: halt.
Deletion from a Binary Tree:To delete the data items from a Binary search tree, there are 4 possible cases which we need to consider. 1. No node in the tree contains the specified data: We need to print the message that the data item is not present in the tree. 2. The node containing the data has no children: Since the node to be deleted has no children, the memory occupied by this should be freed and either the left link or the right link of the parent of this node should be set to NULL. Which of these to set to NULL, depends upon whether the node being deleted is a left child or a right child of its parent. 3. The node containing the data has exactly one child: We have to adjust the pointer of the parent of the node to be deleted, such that after the deletion it points to the child of the node being deleted. 4. The node containing the data has two children: The logic for deleting a node with two children is to locate the inorder successor, copy its data, and reduce the problem to a simple deletion of a node with one or zero children. Algorithm for deletion from a Binary Tree:Function deletetree(S,X) Step1: if(S=NULL) then Print Empty tree return; step2: if ( left(S)==NULL) and (right(S)=NULL) ) then if(data(S)=X) then dispose(S) return; otherwise print Node does not exist return(S) step3: found FALSE step4: q S step5: Repeat step 6 while ((found<>TRUE) or (q<>NULL)) step6: if ( data(q) = X) then // this step is for the searching the node to be deleted

24

found TRUE otherwise if(X < data(q) ) then parent q q left(q) Direction L otherwise parent q q right(q) Direction R step7: if(found = FALSE) print Element not found return(S) step8: if( left(q) = NULL) then q right(q) otherwise if( right(q) = NULL) then q left(q) otherwise parent q; xsucc right(q) repeat while ( left(xsucc) <> NULL) begin parent xsucc; xsucc left(xsucc) end data(q) data(xsucc) q xsucc; step9: if (Direction = L ) then left(parent) q otherwise right(parent) q step10: dispose(q) step11: return(S) step 12: Halt

Applications of Trees:1. It describes the manipulation of arithmetic expressions. 2. It helps in construction and maintenance of symbol tables. 3. It plays important role in the area of syntax analysis.

GRAPHS:
It is a non primitive non linear data structure. Graphs are data structures which have wide ranging applications in real life like, Analysis of circuits, finding shortest routines, statistical analysis etc. A graph consists of two sets v and e, where v is a finite non empty set of vertices and e is a set of pairs of vertices. The pairs of vertices are called edges. A graph can be of 2 types.:-

25

1.Undirected graph: Here the pair of vertices representing any edge is unordered. It is the one where each edge is bidirectional. Thus, the pairs (v1,v2) and (v2,v1) represent the same edge. 2. Directed graph: Each edge is represented by a directed pair <v1,v2>. V1 is the tail and v2 the head of the edge. Therefore <v1,v2> and <v2,v1> represent two different edges. A directed graph is also called digraph. Note: Angular brackets are used for Directed edge, and normal brackets are used for undirected edges. A diagrammatic representation of a graph may have a limited usefulness, However, such a representation is not feasible when the number of nodes and edges in a graph is large. So the alternative method of representing graphs is by using matrices. This method of representation has several advantages. 1. It is easy to store and manipulate matrices and hence the graphs represented by them in the computer. 2. Certain well known operations cab be used to obtain paths, cycles, and other characteristics of a graph. Matrix representation of graph:Let G=(V,E) be a simple digraph in which V={ v1,v2,vn} and the nodes are assumed to be ordered from v1 to vn. An n*n matrix A whose elements are given by, Aij = 1 if (vi,vj) 0 otherwise is called the adjacency matrix of a graph G.

3 2 4 3

G1 G2 Set of vertices= {1,2,3,4} set of vertices= {1,2,3} Set of edges= {(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)} set of edges={ <1,2>,<2,1>, <2,3>} Any element of the adjacency matrix is either 0 or 1. Any matrix whose elements are either 0 or 1 is called a bit matrix or a Boolean matrix. ith row in the adjacency matrix is is determined by edges which originate in the node vi.

26

The number of elements whose value is 1, in ith row is equal to the outdegree of the node vi. The number of elements whose value is 1, in the jth column is equal to the indegree of the node vj. For different ordering of of the elements of V, we will get different adjacency matrices for the same graph. For a null graph, which consists of only n nodes, but no edges, the adjacency matrix has all its elements zero. i.e. adjacency matrix is the null matrix. Weighted graph is a graph where values are given for edges. Disadvantages of matrix representation:1. It is difficult to store additional information about the graph. If information about the node is included, it would be represented by an additional storage structure. 2. It uses static implementation. As the number of nodes must be known before hand to set up the storage array. 3. An insertion or deletion of a node requires changing the dimensions of the array, both difficult and inefficient with large graphs. 4. Complexity increases abnormally with the number of vertices. Adjacency list: This is an another of graph representation. An adjacency list is a listing for each node of all edges connecting it to adjacent nodes. For a graph, G=(V,E), a list is formed for each element x, of V, containing all nodes y, such that (x, y) is an element of V. If an adjacency list is used, each node in the node table directory, must be searched, to determine if the linked list is present, requiring n comparisons.

Adjacency lists for G1 and G2 are:-

For V1 For v2 For v3 For v4

1 1 1

3 2 2

4 4 3

27

G1

For v1 2 For v2 For v3 null N


G2

Graph Traversals:1. Breadth First Traversal: This can be used to find the shortest distance between some starting node and the remaining nodes of the graph. This shortest distance is the minimum number of edges traversed in order to travel from the start node to the specified node being examined. The efficiency of a BFS algorithm is dependent on the method used to represent the graph. The adjacency list representation is suitable for this algorithm, since finding the incident edges to the current node involves simply traversing the a linked list, whereas the adjacency matrix would require searching the entire matrix many times. In this method nodes at same level will be visited first, increasing the level after completing that level nodes. Timing complexity of BFS is O(n+e). where n is the no.of nodes, and e for edges. 2. Depth First search:- This can be used to perform a traversal of a general graph. Since adjacent nodes are needed during the traversal. The most efficient representation again is Adjacency list. In this method, nodes are visited depth wise recursively. It is same as preorder traversal. The time analysis for DFS is O(n+e).

Applications of graphs:1. They are extensively used in Project scheduling.

Spanning Trees: A spanning tree of a graph is an undirected tree consisting of only those edges necessary to connect all the nodes in the original graph. --> For any pair of nodes, there exists only one path between them, and the insertion of any edge to a spanning tree forms a unique circle. 28

-->The cost of a spanning tree is the sum of the weights of the tree edges. --> A minimum cost spanning tree is formed when the edges are picked to minimize the total cost. -->If a depth first search is used, those edges traversed by the algorithm form the edges of the tree, referred to as depth First Spanning Tree. --> If Breadth first search is used, the spanning tree is formed from those edges traversed during the search producing a Breadth First Spanning Tree. -->The most efficient graph representation for this algorithm is an edge list sorted by increasing order of weight. Eg: A

.
A B C D E B F F C

A
D E

DFS

BFS

29

UNIT -5 ASSIGNMENT 1. What is a linked list? What are the different types of linked lists available? 2. Write a C program to form a list containing the union of elements of two lists and another list containing the intersection of the elements of the same two lists? 3. Explain inorder,preorder, postorder traversals with examples? 4. What are the different methods available for representing a graph? 5. Write an algorithm for deleting a node from a Binary search tree? 6. Write a full binary tree of depth 4 with sequential node numbers? 7. Explain with example for Breadth First Search and Depth first search of a graph? 8. Write a program to create a Linear linked list and print out the list? 9. Write algorithms for inserting and deleting nodes from Circular linked list? 10.Write algorithms for inserting and deleting nodes from Doubly linked list? 11. What are spanning trees? Explain the different types of spanning trees available?

30

UNIT-6

Sorting And Searching Techniques


There are several applications in which we store huge amount of data and search for a piece of information within it. We can present the methods that locate the desired thing rather than the way the elements are organized. Basic searching techniques:- Some searching techniques are very faster and few of them are slower in finding the desired element in a file. A file is a meaningful collection of records. There is a key associated with each record which distinguishes them. Search Algorithm:Procedure for searching a desired record with in a given key element is as follows:1. Accept a key element. 2. Search begins and tries to locate the record matching with the given key element. 3. If the desired record is found in a file, then searching process signals Successful message and returns the entire record or pointer to that record. 4. Otherwise, it signals an Unsuccessful message. Searching Techniques: 1. Linear Searching(sequential): This is the simplest of all the searching techniques. An unordered search table is scanned from its first record until the desired record is found. Linear-search(K,N,X). An unordered vector K is given. It consists of N+1 elements. And it searches for X. The function returns the index of the vector element if the search is successful, and returns zero otherwise.

31

1.[Initialize search] I1 K[N+1] X 2. [Search the vector] Repeat while K[I] <> X I I +1 3. [Successful Search] if I= N+1 then write Unsuccessful return(0) else write successful return(1) The first step of the algorithm initializes the key value of the sentinel record to x. In the second step, a sequential search is then performed on the n+1 records. If the index of the record found denotes record R n+1 then the search has failed, otherwise, the search is successful; and I contains the inex of the desired element. the average and worst search time for Linear method is O(n). 2. Binary searching: The entries in the table are stored in alphabetically or numerically increasing order. The appropriate middle entry of te table is located, and its key value is examined. If its value is too high, then the key value of the middle entry of the first half of the table is examined and the procedure is repeated on the first half until the required item is found. function Binary-search(K,N,X) K: It consists of N elements in ascending order. Low : It is the lower limit of the search interval. Middle: It is the upper limit of the search interval. High : It is the upper limit of the search interval. 1. [Initialize] Low 1 High N 2. [Perform Search] Repeat thru step 4 while Low <= High 3. [Obtain index of midpoint of interval] Middle (Low + HIGH)/2 4. [Compare] if X< K[MIDDLE] then High MIDDLE 1 32

else if K > K[MIDDLE] then Low MIDDLE +1 else Write Successful Search return (MIDDLE). 5. [Unsuccessful Search] write Unsuccessful search return. the average and worst search time for Binary search method is O(log2n).

Sorting Techniques
Sorting:Process of re-arranging a given set of elements in a specific (ascending or descending) order. Uses:Used as an aid in searching. As a means for matching entries in files. Applications in operations research and job scheduling. Comparison No. of records Less More More key size --short long Sorting method Selection sort or Bubble sort radix sort quick sort or heap sort or merge sort

If records are initially almost sorted, avoid quick sort method. Internal sorting Methods to be used when the file to be sorted is small enough so that the entire sort can be carried out in main memory. Requires excessive data movement. : Insertion sort Quick sort Heap sort Radix sort Limitation Slows down the sorting process when records are large. 33

External sorting They are the methods that can be used on larger files. Most popular method is Merge sort. Merge sort method It consists of two distinct phases: 1. Segments of the input file are sorted using an internal sort method. The sorted segments (runs) are written out onto external storage as they are generated. 2. The runs generated in phase 1 are merged together following the merge tree pattern until only one run is left. Exchange / Bubble Sort 1. Repeat through step 4 a total of n-1 times. 2. Repeat step 3 for elements in unsorted portion of the array. 3. If the current element in the array > next element in the array then exchange elements. 4. If no exchanges were made then return else reduce the size of the unsorted array by one. Procedure Bubble-Sort (K, N) K Array of N elements PASS Pass counter variable LAST Position of the last unsorted element I Index EXCHS Variable to count the number of exchanges made on any pass. 1. [Initialise] LAST N-1; PASS 1; 2. [Initialise exchanges counter for this pass] EXCHS 0 3. [Perform pair-wise comparisons on unsorted elements]. Repeat for I = 1, 2, , LAST if K[I] > K[I+1] then K[I] K[I+1] EXCHS EXCHS + 1 4. [Any exchanges made on this pass?] if EXCHS = 0 then return else LAST LAST 1; (reduce size of unsorted list) PASS PASS + 1; 34

if PASS = N 1 return else go to Step 2. The time complexity for bubble sort method is: Best case O(n) Average Case O(n2) Worst Case O(n2) Selection Sort Beginning with the first element in the array, a search is performed to locate the element which has the smallest key. When this element is found, it is interchanged with the first element in the array. This interchange places the element with the smallest key, in the first position of the array. A search for the second element with smallest key is then carried out by examining the keys of the elements from the second element onwards. The element, which has the smallest key, is interchanged with the element located in the record position of the array. The process continues until all records have been sorted in ascending order. Procedure Selection_Sort (K, N) K Array of N elements PASS Pass index variable MIN_INDEX Position variable of the smallest element I Index 1. PASS = 1 2. [Initialise minimum index] MIN_INDEX PASS 3. [Make a pass and obtain element with smallest value] repeat for I = PASS + 1, PASS + 2, , N if K[I] < K[MIN-INDEX] then MIN-INDEX I 4. [Exchange elements] if MIN-INDEX PASS then K [PASS] K[MIN-INDEX] PASS PASS + 1; if PASS N then go to Step 2 else return; The time complexity for Selection Sort Method is: Best Case O(n2) Average Case O(n2) Lowest Case O(n2) Quick / Partition Exchange Sort 35

At each step, a particular element is placed in its final position within the list. All elements, which precede this element, have smaller keys/values, while all elements that follow it have larger keys. This technique partitions the list into two sub-lists. The same process can then be applied to each of these sub-lists and repeated until all elements are placed in their final positions. It performs well on larger list of elements. Procedure Quick_Sort(K, LB, UB) K Array of n elements LB lower bound of the current sub-list. UB upper bound of the current sub-list. I, J Index variable KEY key value FLAG logical variable 1. [Initialise] FLAG true 2. [Perform Sort] if LB < UB then I LB J UB + 1 KEY K[LB] Repeat while (FLAG) I I + 1 Repeat while K[I] < KEY (Scan the keys from left to right) I I + 1 J J 1 Repeat while K[J] > KEY (Scan the keys from right to left) J J 1 if I < J then K[I] K[J] (interchange elements) else FLAG false K[LB] K[J] (interchange elements) Call Quick_Sort (K, LB, J 1) (Sort first sub-list) Call Quick_Sort (K, J + 1, UB) (Sort second sub-list) 3. [Finished] Return The time complexity of Quick Sort method is: Best Case O(nlog2n) Average Case O(nlog2n) Worst Case O(n2)

36

Heap Sort:Heap sort method consists of two phases, namely, construction phase and a traversal phase. The construction Phase consists of successively inserting a new element in a tree structure. The tree obtained from this phase can be traversed in inorder. In a list of elements, heap satisfies the property Kj Ki for 2 j n and i = j/2 . The binary tree is allocated sequentially such that the indices of the left and right sons (if they exist) of element i are 2i and 2i + 1, respectively i.e. the index of the parent of element j if (if it exists) is j/2 . The element with the largest key is at the root of the tree (also called the top of the heap). The starting point is to have a heap initially with one element tree and then, insert a new element into the existing heap such that a new heap is formed after performing the insertion. Insertions are performed repeatedly until all elements in the original list form a heap. Procedure CREATE-HEAP (K, N) K Array of N elements Q, I, J Index variable KEY key of the element 1. [Build Heap] repeat thru step 7 for Q = 2, 3, , N 2. [Initialise construction phase] I Q KEY K[Q] 3. [Obtain parent of new element] J TRUNC (I / 2) 4. [Place new element in existing heap] repeat thru step 6 while I > 1 and KEY > K[J] 5. [Interchange element] K[I] K[J] 6. [Obtain next parent] I J J TRUNC (I / 2) if J < 1 then J 1 7. [Copy new element into its proper place] K[I] KEY 8. [Finished] Return Procedure Heap-Sort (K, N) K Array of N elements Q Pass Index variable I Index variable 37

J KEY

Index variable Integer variable

1. [Create the initial heap] Call CREATE_HEAP (K, N) 2. [Perform Sort] repeat thru step 10 for Q = N, N 1, , 2 3. [Exchange element] K[1] K[Q] 4. [Initialise pass] I 1 KEY K[1] J 2 5. [Obtain index of largest son of new element] if J + 1 < Q then if K[J+1] > K[J] then J J +1 6. [Reconstruct the new heap] repeat thru step 10 while (j Q 1 and K[J] > KEY) 7. [interchange element] K[I] K [J] 8. [Obtain next left son] I J J 2 * I 9. [Obtain index of next largest son] if J + 1 < Q then if K[J+1] > K [J] then J J +1 else if J > N then J N 10. [Copy element into its proper place] K[I] KEY 11. [Finished] Return The time complexity of heap sort is: Best Case O(nlog2n) Average Case O(nlog2n) Worst Case O(n2)

Algorithm Selection_sort Bubble_sort Merge_sort Quick_sort Heap-sort

Average Case n2/4 n2/4 O(nlog2n) O(nlog2n) O(nlog2n)

Worst case Space usage 2 n /4 In space n2/2 In space O(nlog2n) Extra n entries. n2/2 Extra log2n entries O(nlog2n) In space

38

Radix_sort O(m+n) O(m+n) Extra space for links Address_cal_sort O(n) O(n2) Extra space for links ____________________________________________________________

UNIT -6 1. What are the different searching and sorting techniques available? 2. Write an algorithm for selection sort? 3. Write a short notes on heap sort? 4. Write an algorithm for Quick sort? 5. Write a program for linear search? 6. Write an algorithm for Binary search? 7. Explain the time complexities for all the searching and sorting algorithms? 8. Explain heap sort technique for the following data? 56 23 10 9 6 19 45 45 23 9. Explain the algorithm for Exchange sort with a suitable example? 10. Analyze worst case performance of quick sort and compare with selection sort?

39