St Joseph’s College ( Autonomous ) Data Structures Using C DATA STRUCTURES USING C Fr Denzil Lobo SJ 1 St Joseph’s College ( Autonomous ) Data Structures Using C STACK Stack is a linear data structure in which data is inserted and deleted at one end ( same end). i.e. data is stored and retrieved in a Last In First Out ( LIFO ) order. The most recently arrived data object is the first one to depart from a stack. Stacks and Queues are very useful in computer science. Stacks are used in compilers in passing an expression by recursion; in memory management in operating system; to convert infix to postfix or prefix expression; etc. Queues find their use in CPU scheduling, in printer spooling, in message queuing in computer network etc. Basic Operations of STACK: Some of the basic operations on stack are: 1. 2. 3. 4. 5. 6. 7. 8. Create a stack Check whether a stack is empty Check whether a stack is full. Initialize a stack. Push an element onto a stack. ( if not full ) Pop an item from a stack ( if not empty ) Read a stack. Print the entire stack. Stacks may be implemented using an ARRAY or a LINKED LIST. Array Implementation: The simplest way to represent a stack is by using a one-dimensional array Data[N] with room for N elements. In C a struct data type as given below may represent it. typedef struct StackType { int Data[20]; int Top; } STACK; STACK S; Where Top points to the top element. And Data is the array which stores the data items. It has provision for at the most 20 items. Functions Associate with the STACK: a) Pushing an Item on to the stack: The prototype of a function in C that pushes an element onto the stack is given below: void Push ( int Item) Algorithm to Push an item onto the stack: If( Top EQ MAXNUM) // MAXNUM is the total capacity PRINT “Over flow” // of the stack Else{ Top Top +1 Data[Top] Item } 2 St Joseph’s College ( Autonomous ) Data Structures Using C Algorithm for Popping an Item from the stack: The prototype of the function to Pop an item from the stack is: int Pop( void ) Algorithm to pop an item: IF( Top EQ 0 ) PRINT “Under flow” ELSE{ Item S[Top] Top = Top –1 } Problems: Write algorithms and C code for the following functions associated with a stack. 1. 2. 3. 4. 5. InitStack( ) to initialize a given stack. StackEmpty( ) which return 1 if empty or 0 if not. DisplayStack ( ) to display the contents of a stack. Push( int Item) to push Item onto the stack int Pop( ) to pop a number from the stack. APPLIACTIONS OF STACK Conversion of a mathematical expression from INFIX to POLISH POSTFIX notation. e.g.: infix expression postfix expression A+B-C+D (A + B)/( C+ D) A+B*C-D A + B* ( C + D *(E + F ) ) (A/B)*(C * F + ( A - D)* E ) AB + C - D + AB+ CD+ / ABC * + D ABCDEF + * + * + AB/CF * AD - E * + * Assumptions: 1. Only capital letters are allowed as variable names 2. No constants are allowed in the expression 3. We restrict ourselves to the four arithmetic operators +, -, * and / 4. We assume that there are no errors in the infix notation. Operator precedence: operator ^ */ +Precedence numbers 5 4 3 ( 2 3 ) 1 St Joseph’s College ( Autonomous ) Data Structures Using C ALGORITHM: 1.Scan the infix expression from left to right 2.if the scanned character is an operand enter it in the infix expression. If it is not an operand then push it into the stack. Before pushing it in, however, the precedence of the operator at the top of the stack is compared with that of the present operator. If the operator at the top of the stack has a higher or same precedence as the present operator, the operator at the top of the stack is popped and appended to the postfix expression. This is repeated and more operators are popped out of the stack till the operator at the top of stack has lower precedence. 3.Whenever a right parenthesis is found in the infix expression it is ignored. At this time the stack will invariably have at the top the matching left parenthesis. This is popped out of the stack and ignored. Do the following to develop this program 1. Write functions to Pop and Push operators on to the stack 2. Write a function to assign the precedence to the operators 3. To store the infix expression to an array and scanned from left to right. 4. Write a function to return tokens ( operator, operand, parenthesis etc ) from the expression. ALGORITHM to convert an INFIX expression to POSTFIX expression: An array of characters stores the infix string. Initially the stack is empty and the Stack pointer is initialized to 0 1. Scan infix_string from left to right one character at a time. 2. While (characters are left in the infix_string){ Switch( scanned_character){ LETTER: Place the scanned character in postfix string; break; OPERATOR: if (stack is empty ){ push the scanned character in the stack break; } else { repeat{ Pop character from the stack If( the precedence of the operator on top of the stack is higher than that of the scanned character operator){ place the character from top of stack in the polish string push the operator } } until (stack is empty or precedence of the popped operator becomes lower than that of scanned character) } if (precedence of operator in stack is low ){ Push character popped from the stack back into it Push scanned character into the stack } else{ Push scanned character into the stack } break; LEFT_PAREN: Push scanned character into the stac break; RIGHT_PAREN: Pop characters from stack and put them in post_fix string till matching left parenthesis is found break; }/* ---end of while 3. Pop out any operators left in stack and append them to the post_fix string. 4 scanned St Joseph’s College ( Autonomous ) Data Structures Using C Problem: Using the above algorithms show how an infix expression is converted into postfix expression for the following mathematical expression. A*(B + C) * D Next token A * ( B + C ) * D NOMORE Stack empty * *( *( *(+ *(+ * ( pop till left paren ) * * empty Output expression A A A AB AB ABC ABC+ ABC+* ABC+*D ABC+*D* Problems: Show the working of a stack for the conversion of the following infix expressions into postfix expressions. 1) ( A + B)/( C + D) 3) A + B*(C + D*( E + F )) 2) A + B * C + D 4) (A/B)*(C * F + (A – D)*E) 5 St Joseph’s College ( Autonomous ) Data Structures Using C The code below gives the different functions and the main program involved in conversion of an INFIX expression to POSTFIX expression. FUNCTIONS to Push and Pop OPERATORS 6 St Joseph’s College ( Autonomous ) Data Structures Using C FUNCTION to convert INFIX expression into POSRFIX expression: 7 St Joseph’s College ( Autonomous ) Data Structures Using C Home Work: Write the following functions to convert the infix expression to postfix expression. 1. void Push( char Op) to push an operator onto the stack 2. char Pop(void ) to pop an operator from the stack 3. void InitStack( void) to initialize the stack 3. void GetExpr( void ) to input an infix expression into the array InFix[] 4. int ScanExpr( char *Optr, char *Oprnd)to scan the Infix Expression and return one of the following tokens: OPERAND OPERATOR LEFTPAREN RIGHTPAREN NOMORE 1 2 3 4 0 The arguments Optr and Oprnd also return corresponding operator or operand. 5. int Precedence(char Op)to return the precedence value of operators operator ^ */ +( ) Precedence numbers 5 4 3 2 1 6. int StackEmpty() function to check if the stack is empty. 7. Return 1 if empty else 0. STACK: Evaluation of integer POSTFIX expression In the postfix form, also called the reverse Polish notation, each operator follows its operands, and parenthesis are not needed. Thus an infix notation for the expression: 1+(2*3) is written in the post fix form as: 12 3*+ We assume that the integer expressions use only four binary operators +, -, *, and /, and that the terms of these expressions are separated by white spaces. The implementation is simple. Each operand is pushed onto a stack; When an operator arrives, the proper number of operands (two for binary operations ) is popped, the operator is applied to them, and the result is pushed back onto the stack. The result is popped when the end of the expression is reached. Algorithm: while( next operator or operand is not end-of-file indicator){ IF( number ) push it ELSE IF ( operator){ pop operands do operation // addition, multiplication etc. push result } ELSE error } POP and print the result. 8 St Joseph’s College ( Autonomous ) Data Structures Using C Problem: Using the above algorithm show how stack is used to evaluate the following postfix mathematical expression 5 10 + 10 5 - / Answer: tokens 5 10 + 10 5 / NOMORE stack 5 5 10 15 15 10 15 10 5 15 5 3 EMPTY Pop both, add and push Pop two numbers, deduct and push 3 : Pop the answer Problems: First convert the following infix expression to post fix and show how stack is used to evaluate the postfix expressions. 1. ( 10 + 5)^ 2 /( 15 – 5) 2. 5 + 2 * 5 – 10 / 2 9 St Joseph’s College ( Autonomous ) Data Structures Using C The following code for the evaluation of a Postfix expression. /*-------------------------------------------------------------------------------------------------------------------EVALPOST.C Program that evaluates the post fix notation.. Meant only fr single digit numbers. Input: integer number with operators ^, *, /, + and --------------------------------------------------------------------------------------------------------------------*/ 10 St Joseph’s College ( Autonomous ) Data Structures Using C PROBLEMS: 1. Write a program to determine if an input character string is of the form XaY. X is a string of arbitrary length using only characters A and B. for example, X may be ABBAB. Y is a string, which is reverse of X. Thus for the string X given above ZY, is BABBA. A is any arbitrary character which is not A or B. For example given ABAACABAB the program should write a message that this string is invalid. For the string ABBABCBABBA the program should write a message that it ios valid. Use a stack to do this. 2. Write a program to read a parenthesized infix expression and do the following. i) Check if the left and right parenthesis match ii) If they match, then remove all excess superfluous parenthesis and create an infix string with minimum number of parenthesis. 3. Show how stack is used to evaluate the following problems. i) Factorial of a number ii) an iii) Generate fibonacci number iv) Solve Ackerman function. Mini Projects: 1. 2. Design a calculator using the following operators ( ^, * , /, + , -) to evaluate an infix expression. Show how Tower of Hanoi can be solved graphically using stacks. 11 St Joseph’s College ( Autonomous ) Data Structures Using C LINKED LIST A list is a sequence of zero or more elements of a given type. Lists arise routinely in applications such as information retrieval, programming language translations, and simulation. Arrays can be used to implement lists, but have the disadvantage that the insertion or deletion of elements in the middle of a list requires shifting of elements to make room for the new elements or to close up gaps created by deleted elements. An array implementation may also waste space because the maximum space is used irrespective of the number of elements actually in the list. On the other hand, the maximum size if underestimated may cause runtime error. In the linked implementation of a list, pointers are used to link successive list elements. A singly linked list is made up of nodes, each node consisting of an element of the list and a pointer to the next node on the list. The node containing the last element has a NULL pointer. This indicates the end of the list. The first element is usually referred to as the head of the list, and the last element, as the tail of the list. There is also a list pointer, which points to the head of the list. 20 list pointer 34 25 head 10 tail The advantage of linked list is that the list elements can be inserted and deleted by adjusting the pointers without shifting other elements, and storage for a new element can be allocated dynamically and freed when an element is deleted. Basic operations performed on a LIST: 1. Create a node 2. Create a list 3. Check for an empty list 4. Search for an element in a list 5. Search for a predecessor or a successor of an element of a list 6. Delete an element in a list 7. Add an element at a specified location of a list 8. Retrieve an element in a list 9. Update an element in a list 10. Sort a list 11. Print a list 12. Determine or size of a list 13. Delete a list Creation of a Node of the Linked List: Suppose we want to create a node in a singly linked list with integer data item, we could define the following structure in C. typedef struct ListNode{ int Num; struct ListNode *Next; }LISTNODE; 12 St Joseph’s College ( Autonomous ) Data Structures Using C The following function in C dynamically allocates memory for the node of the linked list and returns the address of the node. Creation of a Linked List: version I: We could think of the creation of a linked list in the order the positive integers arrive. Suppose the following numbers arrive in the order given below. 20 34 25 10 then the linked list built out of these numbers will be: 20 34 25 10 list ptr To create such a linked list we follow the following steps. 1. 2. 3. 4. Allocate storage for a node Put the number in the new node If there is no other node make it the head node Else add the new node at the end of the last node. C code for the function subprogram to insert a node into a list: In this algorithm we keep track of the current node ( Curr) and the previous (Prev) node traversed. Assign the pointer of the head node to the current node and make the previous node NULL. The list is traversed as long as the node is not equal to NULL. The new node is appended to the previous node when the current node is NULL. In case the previous node is NULL ( that is, if there are no items in the list ) after the traversal, we make the new node, the head of the list. 13 St Joseph’s College ( Autonomous ) Data Structures Using C Problem: Write a c program using functions to create a linked list out of coefficients and powers of a polynomial. Display the polynomial. Creation of a Ordered Linked List version II: There are three cases of inserting a node into a linked list i) Node to be inserted at the beginning of the list ( make it the head of the list ) ii) Node to be inserted in between any other two nodes and iii) Node to be inserted at the end of the list (make it tail of the list). Case 1: 7 11 15 24 5 algorithm: // ---------p, curr, head are pointer variables Node = MakeListNode( Num) Curr= Head if( Num < Curr->Num){ Node->next = Curr Head = Node } 14 St Joseph’s College ( Autonomous ) Data Structures Using C case 2: Insertion of the node in the middle of the list Suppose we want to insert 13 into the ordered linked list represented above. First we create a node ( p ) out of the data item 13. Then traverse the list starting from the head of the list, come to the exact location where we have to insert the node. During the traversal of the list we keep track of the nodes we cover.This is done using two pointer variables prev(previous ) and curr(current). We traverse the list till the number on the current node is greater than the incoming number(13). At that point the pointer variable prev would refer to the node contain ing 11 and curr would refer to the node containing 15. At this point, we attach the curr node to the end of the node p and attach p at the end of prev node as shown below. 7 11 15 prev 24 curr 13 Algorithm: Node = MakeListNode( Num) Prev= NULL Curr = Head while ( Curr and Curr->Num < Num){ Prev = Curr Curr = Curr->Next } Node->Next = curr Prev->Next = Node Case 3: Attaching the node at the end of the list Suppose we want to insert 30 into the linked list. To do this once again traverse the linked list from the Head, keeping track of the Prev and Curr addresses of the nodes traversed. since 30 is greater than the number in the last node of the list, the address of Curr will be NULL when we reach the end of the list. At this point, the new node containing 30 is attached to the Prev node (the node containing 24 ) as shown below. 7 11 15 24 30 Algorithm: Prev = NULL Curr = Head Node = MakeListNode( Num ) WHILE( Curr AND Curr->Num < Num ){ Prev = Curr Curr = Curr->Next } Prev->Next = Node 15 St Joseph’s College ( Autonomous ) Data Structures Using C C code for function to insert a Number into a linked list: The above three cases are incorporated in the C code given below. Since the head is a pointer variable, we need to declare it as pointer to pointer ( ** head) to obtain the address value of the head node. 16 St Joseph’s College ( Autonomous ) Data Structures Using C Displaying the List: The algorithm to display the content of a linked list is given below. Algorithm: LISTNODE *Curr Curr = Head while( Curr ){ PRINT ( Curr->Num ) Curr = Curr->next } Problems: 1. Write a program in C to create a linked list with integer number as the data item in the node. 2. Write a function which, given a pointer to a linked list, returns the number of nodes in the list. 3. Write a function, which given a pointer to the linked list and key, searches the key in the list. If found, returns a pointer to the node in which key is found, otherwise returns NULL. 4. The letters of a work are stored in a linked list, one letter per node. Write a C statement to reverse the letters of the word. 5. Write a function, which determines if the nodes in a list are in order. 6. Write a function which, given a pointer to the linked list, returns a pointer to the last node of the list. 7. A linked list is used to represent a polynomial, each element of the list representing one ( nonzero ) terms of polynomial. The ‘data’ for each node consists of a coefficient and an exponent. The terms are stored in order of decreasing exponent and no coefficient is 0. Write a function to read ( coefficient, exponent ) pairs and create the linked list representing a polynomial. 8. Write a function to sort a linked list of integers as follows. a) find the node with the smallest value in the list b) Interchange its ‘data’ with that at the top of the list. c) Starting from what is now the second element, repeat (a) and interchange its ‘data’ with that of the second element. Applications of Linked List: Polynomial Addition & Multiplication Polynomials may be represented using linked list. Each term of a polynomial is represented by a node having the coefficient, exponent and a link to the next term as shown below. Coef Expo Coef Expo Coef 17 Expo St Joseph’s College ( Autonomous ) Data Structures Using C The data structure for the node is given below: typedef struct PolyNodeType { double Coef; int Expo; struct PolyNodeType *Next; }POLYNODE; 1. Creation of a node by dynamic memory allocation: The term of the polynomial containing the coefficient and the exponent values is created by the following function. The function returns the address of the node. POLYNODE *MakePolyTerm( double Coef, int Expo ) { POLYNODE *p; p = ( POLYNODE *) malloc( sizeof ( POLYNODE )); p->Coef = Coef; p->Expo = Expo; p->Next = NULL; return p; } 2. Insertion of a TERM into a Polynomial list: We presume that each node follows the descending order of exponent value. From the values of the coefficient and the exponent, a node is created. Then we transverse the list to locate the last node. And then attach the new node at the end of the list as shown by the following function in C. The argument head gives the address of the starting node of the polynomial list. void InsertPolyNode( POLYNODE *p, POLYTERM **Head ) { POLYTERM , *Prev, *Curr; Prev = NULL; Curr = *Head; /*-------------search for the end of the list --------*/ while( Curr ){ Prev = Curr; Curr = Curr->next; } /*------if there is no other node, make it the head of the list----*/ if( Prev = = NULL) *Head=p; else Prev->Next = p; return p; } 18 St Joseph’s College ( Autonomous ) Data Structures Using C 3. Adding Polynomials: The following algorithm given in pseudocode shows how two polynomials are added. POLYNODE * AddPoly( POLYTERM *P, POLYETERM *Q) { POLYTERM *Head, *T Coef, Expo /* initialize head and tail of the polynomial to NULL --*/ head = NULL while(P <> NULL AND Q <> NULL){ if( P->Expo == Q->Expo){ // exponents are equal Coef = P -> Coef + Q -> Coef if( Coef < > 0){ Expo = )->Expo T = MakePolyNode( Coef, Expo ) InsertTerm( T, &Head) P = P ->next Q = Q->next } } else if( P->Expo > Q->Expo ){ // exponent of P is greater InsertPolyNode( P, &Head ) P=P->next } else{ InsertPolyNode( Q , &Head ) Q = Q->next } } while (P <> NULL){ InsertTerm(P, &Head ) P = P -> next } while(Q <> NULL){ InsertTerm ( Q, &Head ) Q = Q ->next } return Head } Questions: 1. Write a function which, given a pointer to a linked list, returns the number of nodes in the list. 2. Write a function, given a pointer to a linked list and key, searches for the key in the list. I found, returns a pointer to the node in which key is found, or returns NULL. 3. Write a function, which determines if the nodes in a list are in order. 4. Write a function which, given a pointer to a linked list, returns a pointer to the last node of the list. 5. Write a function, which given pointers to two sorted linked lists of integers merges the two lists into one sorted list. No new storage should be allocated for the merged list. The merged list should consist of the original cells of the given lists; only pointers should be changed, The function should return a pointer to the merged list. 19 St Joseph’s College ( Autonomous ) Data Structures Using C 6. The letters of a word are stored in a linked list, one letter per node. Write C statements to reverse the letters of the word. 7. Write a function to multiply two polynomials. Let the function return a pointer to the list containing the product of two polynomials. 8. Write a program in C to insert the words from a given text file into a linked list. Let the node indicate how many times and where the word occurs in the text. 9. Write a program to read the records from a data file and store them in a linked list and sort them using quick sort. Sort the records on the key of your choice. 10. Write a c function to delete a given item from a linked list. 11. Write a function to traverse a linked list and pick all the odd numbered nodes and place them in the beginning of the list and the rest will be even numbered nodes. e.g. if a list contains 5 10 8 7 30, the new list would have the following sequence : 5 8 30 10 7 12. Write a function to delete all even nodes in a linked list. CIRCULAR LINKED LIST: Another alternative to overcome the drawback of singly linked List structure is to make the last element point to the first element of the List. The resulting structure is called a circularly linked list. It is represented as shown below. Front 3 Rear 10 8 15 C program code for creating a circular list is given below. 20 St Joseph’s College ( Autonomous ) Data Structures Using C Assignment: 1. Write a program that makes a list of chemical elements and then makes the data available on demand. The program first builds the list by prompting the technician by atomic number to enter the elements full name, symbol, the atomic weight. It then prompts the chemist to enter an elements symbol and prints the rest of the info. 2. Write a function that takes a pointer to a linked list and reverses the order of the nodes by simply altering the pointers. SPARSE ARRAYS: Sparse arrays are special arrays, which arise commonly in applications. It is difficult to draw the dividing line between the sparse and non-sparse array. Loosely an array is called sparse if it has a relatively number of zero elements. for example: 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 3 0 4 2 1 0 0 0 0 0 0 21 0 0 0 0 0 0 0 St Joseph’s College ( Autonomous ) Data Structures Using C If we store the contents of this array in a regular array we will be wasting a lot of space. Therefore in order to save space the following two representations are used to store a given sparse array. These methods store only the non-zero elements. They are: a) Vector representation b) Linked List representation. a) Vector Representation A sparse matrix is represented by another 2D array of the form: A(0...n, 1..3). Where n is number of non-zero elements. For example the above sparse matrix may be represented as: 0 1 2 3 4 5 6 1 7 1 2 4 5 6 7 2 7 6 5 5 2 5 5 3 6 1 1 3 2 4 2 Number of columns, rows and non-zero elements in the sparse array In this representation, the columns 1 and 2 of the matrix represent the row and column of the non-zero element in the sparse matrix, and the 3rd column gives the non-zero term. If the sparse array were one-dimensional, a pair would represent each non-zero element. In general for an N-dimensional sparse array, non-zero elements are represented by an entry with N+1 values. b) Linked List representation: In this representation each element of a sparse array is stored in a linked list of 3 tuples as shown below. The first element represents the row; the second, the column and the third element is the non-zero term. linked list for a sparse array 1 6 1 2 5 1 4 5 3 Problems: 1. Write a program in C using user defined functions to add and multiply two sparse matrices. 2. Write a functions to create a linked list of sparse matrix and to display it in matrix form. 22 St Joseph’s College ( Autonomous ) Data Structures Using C DOUBLY LINKED LISTS: In the LIST discussed in the previous section, we traverse the LIST in one direction. In many applications it is required to traverse a List in both directions. This 2-way traversal can be realized by maintaining two link fields in each node instead of one. We call such a structure a Doubly Linked List. Each element of a doubly linked List structure has three fields. * data value * a link to its successor * a link to its predecessor The predecessor link is called the Left link and the successor link is known as the right link. The traversal of the List can be in any direction. We have a structure as given in fig. We note that the left link of the leftmost node and the right link of the rightmost node are NIL. Head tail Data data data Insertion of a node in a doubly Linked List: To insert a node into a doubly linked List to the right of a specified node, we have to consider several cases. These are as follows: 1. If the List is empty, i.e the left and right link of specified node is pointed to a variable are nil. An insertion of this node is simply making the left and right link to point to the new node and left and right link of new node to be set to nil. 2. If there is a predecessor and a successor to the given node, then we need to readjust links of the specified node and its successor node. The procedure may be depicted as given below: NIL data Data data data data data data data data 3. If the insertion is to be done after the right most node in the list, then, only the right of the specified node i.e, the rightmost node is to be changed. 23 St Joseph’s College ( Autonomous ) Data Structures Using C C Code for creating a doubly Linked List: The C code for creating a doubly linked list is given below. /*-------------DblLink.C----------------------------*/ # include <stdio.h> typedef struct DblLnkListType{ int Num; struct DblLnkListType *Prev; struct DblLnkListType *Next; }DBLLNKNODE; DBLLNKNODE *Head; // declared as GLOBAL variable. 24 St Joseph’s College ( Autonomous ) Data Structures Using C PROBLEMS: 1. Write C routines to do the following in a linear sequential list: a) Append an element to the tail of the list. b) Concatenate two lists. c) Reverse a list so that the last element becomes the first and vice versa. d) Insert a node as the nth node of the list. e) Copy a list into another. f) Count the number of nodes in a list. g) Delete all even nodes in the list. h) Interchange the nth and kth nodes of a list. 2. Create a data structure, which would represent the record of each member of library. The records should contain membership number, name, borrower category and a part, which could contain a list of books borrowed by a member. 3. Write a function, which could scan the member data structure and print out the books borrowed by a specified member. 4. Write a function, which would print out the names of all members who have borrowed more than 6 books. 5. Write a function to merge the two sorted lists. 6. Define a list data structure to facilitate the symbolic manipulation of polynomials. For example a term of the polynomial may be represented by the node: a) Write a routine to add two polynomials represented by two lists. b) Write another routine to symbolically differentiate a polynomial and obtain a list, which represents the derivative symbol. 25 St Joseph’s College ( Autonomous ) 7. Data Structures Using C Represent a sparse vector by a circular list. 8. Write a routine to add two sparse vectors. 9. Design double linked circular lists to store the following sparse matrix. Pictorially show the lists to represent this matrix. 2 0 0 4 0 0 5 0 0 7 0 0 1 4 0 0 10. Write a program to add two n x n sparse matrices and store the results in a third matrix. 26 St Joseph’s College ( Autonomous ) Data Structures Using C TREE DATA STRUCTURE Tree is a non-linear data structure with relationships other than adjacency, such as parent, children, siblings are present. DEFINITION (General tree) A tree is a finite set of one or more nodes such that 1. There is a specially designated node called the root. 2. The remaining nodes are partitioned into n > o disjoint set T1,T2 ... Tn where each of these sets is a tree, where T1,T2 ... Tn are called subtrees of the root. There are many terms which are often used when referring to trees. Consider the tree in figure 1 Root A B Level 1 C D Level 2 E F G H I J Level 3 K L M Figure 1 General tree Level 4 This tree has 13 nodes, each data items of a node being a single letter for convenience. The root contains A and we will normally draw trees with the root as the top. The number of subtrees is called its degree. The degree of A is 3, B is 2, C is 1 and G,F,I,J is 0. Nodes that have degree 0 are called LEAF or terminal nodes. The set {K,L,F,G,M,I,J} is the set of leaf nodes. B,C and D are children of A. A is the parent of its children. The children of D are H,I,J are siblings. The degree of a tree is the maximum degree of nodes in the tree. The tree in the figure 1 has the degree 3. The level of node is defined by initially letting the root be at level one. If a node is at level p, then its children are at level p+1. The height or depth of a tree is defined to be the maximum level in the tree. The height of the tree in this case is 4. BINARY TREE Binary tree is characterized by the fact that any node can have at most two children, that is no node with degree greater than two. For binary trees we distinguish between the subtree on the left and on the right, where as for trees the order of the subtree is irrelevant. A B E D F H Figure 2 Binary tree 27 St Joseph’s College ( Autonomous ) Data Structures Using C Definition A binary tree is a finite set of nodes which is either empty or consists of a root and two disjoint binary trees called the left and right subtrees. A A B B C C Right Skewed tree Left Skewed tree Figure 3 Skewed tree Left skewed tree : A binary tree with only left subtree is called left skewed tree. Right skewed tree : A binary tree with only right subtree is called right skewed tree. The maximum number of nodes at a level I of a binary tree is 2 I-1 and also the maximum number of nodes in a binary tree of depth K is 2 k - 1, K > 0. The binary tree of depth K which has exactly 2 k-1 nodes is called full binary tree of depth k. A very elegant sequential representation for full binary trees results from sequentially numbering the nodes, starting with nodes on level one, then going to those on level two and so on. Nodes on any level are numbered from left to right. A binary tree with n nodes and of depth K is complete if its nodes correspond to the nodes which are numbered one to n in a full binary tree of depth K. A consequence of this definition is that in a complete binary tree, leaf nodes occur on at most two adjacent levels. MEMORY REPRESENTATION OF A BINARY TREE There are two types of memory representation 1. Sequential representation 2. Linked list representaton Sequential representation In a sequential representation arrays are used to store the binary tree. The nodes of a complete binary tree may be completely stored in one dimensional array TREE with the node numbered I being stored in TREE(I). The following rule shows us how to easily determine the locations of the parent, left child and right child of any node. I in the binary tree without explicitly storing any link information. If a complete binary tree with n nodes is represented sequentially as described before, then for any node with index I, 1 < I < n, we have 1. PARENT (I) is at [I/2] if I <>1 , when I=1, I is root and has no parent. 2. LCHILD (I) is at 2I if 2I <=n, If 2I >n has no left child. 3. RCHILD (I) is at 2I+ l if 2lI+ 1 <=n, If 2I + 1 >n then I has no right child. This representation can clearly be used for all binary trees though in most cases there will be s lot of unutilized space. 28 St Joseph’s College ( Autonomous ) Data Structures Using C example 1: Consider a binary tree in figure 3 A1 2 B C E 3 F 5 7 Here the nodes are numbered according to full binary tree. The number of nodes in a full binary tree of level 3 is 23 - 1 =7. We require an array of size 7. Figure 4 shows the array representation. 1 A 2 B Figure 4 3 C 4 - 5 E 6 - 7 F Memory Representation of a Binary tree Example 2: Declare an array of size 25-1 , store the information in the corresponding location of the node number. Figure 5 shows the array representation. 1 2 4 8 16 1 A 2 B 3 - 4 C A B C D E 5 - 6 - 7 - 8 D 9 - ..... - .... - 16... E ...31 ---- Figure 5 Memory representation of a binary tree Linked list representation of a binary tree Consider a binary tree T. Each node of the binary tree consists of three fields: 1. Information about the nods (data item). 2. Left link which contains the memory location of left subtree of node N. 3. Right link which contains the memory location of right subtree of node N. Left link and right link are the pointer type fields. Root is a pointer variable contains address of the root node. Example 3: A B D R E 29 C J St Joseph’s College ( Autonomous ) Data Structures Using C ROOT A B Null Null D C Null Null E R Null Null J Null Null Figure 6 Linked list representation of a binary tree K-ary(N-ary) Tree K-ary tree is one in which degree of each node in the tree is at most K. 2-ary tree is a binary tree. 3-ary tree is a general tree. TREE TRAVERSALS OF A BINARY TREE Traversing a binary tree is visiting all the nodes exactly once and performing some operation. 1. Preorder traversal i. Process the root node R ii. Traverse the left subtree in preorder iii. Traverse the right subtree in preorder 2. Postorder traversal i. Traverse the left subtree in postorder ii. Traverse the right subtree in postorder iii. Process the root node R 3. Inorder traversal i. Traverse the left subtree in inorder ii. Process the root node R iii. Traverse the right subtree in inorder In a preorder traversal the root R is processed before the subtrees are traversed. It is called node-left-right (NLR) traversal. In Inorder traversal the root R are is processed between the traversals of the subtrees. It is called left-node-right (LNR) traversal. In postorder traversal the root R are is processed after the traversals of the subtrees. It is called left-right-node (LNR) traversal. Example 4:Consider a binary tree T in Figure 7. Observe that A is the root, that its left subtree LT consists of nodes B,D and E and that its right subtree RT consists of node C and F 30 St Joseph’s College ( Autonomous ) Data Structures Using C . A B C LT RT D E F Figure 7 a) The preorder traversal of T process A, traverses LT and traverses RT. However the preorder traversal of LT process the root B then D and E, and the preorder traversal of RT process the root C and then F. Hence ABDECF is the preorder traversal of T. b) The inorder traversal of T traverses LT, process A and traverses RT. However the inorder traversal of LT process the D,B then E, and the inorder traversal of RT process C and then F. Hence DBEACF is the inorder traversal of T. c) The postorder traversal of T traverses LT, traverses RT, and process A. However the postorder traversal of LT process D,E and then B, and the postorder traversal of RT process F and C. Accordingly, DEBFCA is the postorder traversal of T. BINARY SEARCH TREE This structure enables one to search for and find an element with running time f(n)=O(log n) but it is expensive to insert and delete elements. This structure contrasts with the following structures: i. Sorted liner array : Here one can search for and find an element with a running time f(n) = O(log n) but it is expensive to insert and delete elements. ii. Linked list : Here one can easily insert and delete elements but it is expensive to search for and find an element, since one must use a linear search with running time f(n)=O(n). Suppose T is a binary tree, then T is called a Binary search tree if each node N of T has the following property : The value at N is greater than every value in the left subtree of N and is less than every value in the right subtree of N. Note : Inorder traversal of T will yield a sorted listing of the elements of T Example 5: 38 14 8 56 23 18 45 82 50 Figure 8 Binary search tree 31 St Joseph’s College ( Autonomous ) Data Structures Using C SEARCHING AND INSERTING IN A BINARY SEARCH TREE Suppose T is a binary search tree. The searching and inserting will be given by a single search and insertion algorithm : Algorithm 1: Suppose ITEM of information is given. The following algorithm finds the location of ITEM in the binary search tree, or inserts ITEM as a new node in its appropriate place in the tree. 1. Compare ITEM with the root node N of the tree. a. If ITEM < N, proceed to left child of N b. If ITEM > N, proceed to the right child of N. 2. Repeat step 1 until one of the following occurs : a. We meet a node N such that ITEM = N. In this case search is successful. b. We meet an empty subtree which indicates that search is unsuccessful and we insert ITEM in place of the empty subtree. In other words, proceed from the root R down through the tree T until finding ITEM in T or inserting ITEM as a terminal node of the T. Example 6: Consider a Binary tree T in figure 38 14 8 56 23 45 18 82 50 Figure 9 Suppose ITEM = 20 is given. Tracing the above algorithm. We obtain the following steps. 1. Compare ITEM = 20 with the root 38 of the tree T. Since 20 < 38, proceed to the left child of 38, which is 14. 2. Compare ITEM = 20 with14. Since 20 > 14 proceed to right child of 14, which is 23. 3. Compare ITEM = 20 with 23. Since 20 < 23, proceed to the left child of 23, which is 18. 4. Compare ITEM = 20 with 18. node 18 does not have any child, insert 20 as right child of 18. Figure 10 shows the new tree with ITEM = 20 inserted. The shaded edges indicate path down through the tree during the algorithm. 38 14 8 56 23 45 18 82 50 20 32 St Joseph’s College ( Autonomous ) Data Structures Using C CONSTRUCTION OF BINARY SEARCH TREE The above Algorithm 1 can be applied successively to each element to build a binary search tree. Example 7 : Suppose the following six numbers are inserted in order into an empty binary search tree 40, 60, 50, 33, 55, 11 The figure 11 shows the six stages of tree. 40 40 60 !. ITEM = 40 40 40 60 50 2. ITEM = 60 4. ITEM = 33 40 33 33 50 3. ITEM = 50 40 60 33 60 60 50 11 50 55 55 5. ITEM = 55 6. ITEM = 11 Figure 11 Algorithm to Add a node to a binary search Tree: AddNode( node, value){ If( two values are the same ) { Duplicate Return failure }Else if( value < value stored in current node ) { If( left child exists) AddNode( leftChild, value ) Else{ Allocate new node and make left child point to it Return( SUCCESS ) } }Elseif ( value > value stored in current node) If( right child exists) AddNode( rightChild, value ) Else{ Allocate new node and make right child point to it Return (SUCCESS) } } } 33 St Joseph’s College ( Autonomous ) Data Structures Using C DELETING IN A BINARY SEARCH TREE Suppose T is a binary search tree and suppose an ITEM of information is given. ITEM will be deleted from the binary search tree T. Algorithm 2: The deletion algorithm uses a search algorithm to find the location of node N containing ITEM and also parent of N denoted by P(N). The way N is deleted from the tree depends on number of children of node N. They are three cases : 1. If N has no children, then N is deleted from T replacing the location of N in P(N) by NULL pointer (empty subtrees) 2. If N has exactly one child then N is deleted from the T by simply replacing the location of N in P(N) by location of only child of N. If N has two children then N is deleted from T by first deleting S(N) ( S (N) denotes the inorder successor of N) from T (by using step 2 or step 3) and then replacing node N in T by node S(N). Example 8: Consider the binary tree T shown in Figure 12 Case 1: Node with no children 60 60 25 15 75 50 25 66 15 33 15 66 66 33 50 15 33 Node 75 is deleted Here the parent node4460. So 75 is deleted. The child node of 75 i.e,. 66 is made as the child node of 60. 50 33 Node 44 is deleted Case 3 : Node with two children 60 Before deletions Case 2 : Node with one child 44 60 25 75 75 50 66 44 25 is deleted Node Here 33 is the inorder successor of node 25. The deletion is accomplished by first deletion 33 using case 2 and then replacing node 25 by 33 Figure 12 34 St Joseph’s College ( Autonomous ) Data Structures Using C Applications of Trees 1. It is used to represent hierarchical relationship. 2. It is used in the construction of symbol table. Example 9: Write a Binary tree T for the following Preorder and Inorder traversal. Preorder : FAEKCDHGB Inorder : EACKFHDBG Example 10 : Consider the algebraic expression t = (2x + y) (5a -b)3 Here we have to consider the hierarchy of arithmetic operators. While writing the binary tree we have to make the operation which will be executed last as the root node. Similarly for left child whatever the operator that will be executed before the last and also for the right child. In this expression (2x+y) is evaluated and (5a-b)3 is evaluated and then both are multiplied. * (5a - b)3 (2x - y) Further splitting (2x-y), - operation is performed last. -- y 2x Further splitting (5a - b) 3 Further splitting -- * -3 y * 2 b x Final tree would have the * 5 35 a St Joseph’s College ( Autonomous ) Data Structures Using C -- * -- y 3 * 2 x b 5 structure for theaexpression (2x+y) (5a-b)3 Figure 10.14 Tree Example 10.11 : Write preorder and postorder expressions for the following inorder expression : [ a + ( b - c ) ] / [ ( f + g - h) * d ] and also draw the tree structure. Preorder expression [a+(b-c)]/[f+g-h)*d] = [ a + (-bc) ] / [ ( ( +fg ) - h ) * d ] = [ +a - bc ] / [ (- +fgh) * d ] = [ +a - bc] / [ *- +f ghd ] =/+a-bc *-+fghd =[a+(b-c)]/[(f+g-h)*d] Postorder expression = [ a + (bc-) ] / [ ( (fg +) - h ) * d ] = [ abc - + ] / [ (fgh +-) * d ] = [ abc - + ] / [ fgh + - d * ] =abc-+fg+h-d*/ / + * - a b d - c + f h g Figure 10.15 Tree structure for the expression [ a + ( b - c) ] / [ ( f + g - h) * d ] Example 10.12 : Consider the algebraic expression F = (3a - b) (6x + y)3 (a) (b) (c) Write the Preorder expression of F. Write the Postorder expression of F. Draw the tree T which corresponds to the expression F. 36 St Joseph’s College ( Autonomous ) (a) (3 a - b ) ( 6x + y) = ( 3 * a - b) * (6 * x + y ) ^ 3 = ((*3a) - b) * ((*6x) + y) ^ 3 = ( - * 3ab) * ( +*6xy)^3 = ( - *3ab) * (^+*6xy3) = * - * 3 a b ^ + * 6 x y3 Preorder expression (b) Data Structures Using C = ( 3 * a - b) * ( 6 *x + y) ^ 3 = (( 3a*)-b) * ((6x *) +y)^ 3 = ( 3a*b-) * (6 x*+) ^ 3 = (3a *b-) * (6x*y+3^) Postorder expression = 3 a * b - 6 x * y + 3 ^ * ^ - b * * 3 3 + y a 6 x Figure 10.16 Tree structure for the expression (3 a - b) ( 6 x + y)3 Questions: 1. What is the prefix notation of the infix expression A + ((B-C)*D) ? 2. Write the infix equivalent of the prefix form : +-*ABCD/E/F+GH 3. What is the maximum number of nodes that a binary tree can have at level 3 ? 4. Write the postfix notation for the expression : A * B – C ^D + E/F 5. Draw the tree diagram corresponding to : x = a(b+(c-d)/( c + f) y= A + B/C*(D+E) – F 6. What is a tree ? Define a K-ary tree. 7. Define the degree of a node. 8. Define child, parent node in a tree. 9. Define the height of the tree. 10. What is a binary tree ? 11. What is the result of inorder traversal of a binary search tree ? 12. What are the applications of trees? 13. What is the maximum number of nodes of a Kth level binary tree ? 14. Name different methods of binary tree traversal. 15. Write an algorithm for searching an element in a binary search tree. 16. Write an algorithm to insert an element into a binary tree. 17. Write an algorithm to delete an element in a binary search tree. 37 St Joseph’s College ( Autonomous ) Data Structures Using C Code segments in C for some of the functions used in creating a Tree structure are given below. The node of a BST containing integer data item may be declared as: typedef struct TreeNodeType{ int Num; struct TreeNodeType *Right; struct TreeNodeType *Left; }TREENODE; /*----------MakTreeNode: to create a node --------------------*/ Prob: Write a function in C to dynamically allocate memory to store data item in a node of a tree. TREENODE *MakeTreeNode( int Num ) { TRENODE *Node; Node = (TREENODE *)malloc( sizeof ( TREENODE )); Node→Num = Num; Node→Left = NULL; Node→Right= NULL; return p; } Insertion of a node into a BINARY SEARCH TREE- Non Recursive Implementation: 38 St Joseph’s College ( Autonomous ) Data Structures Using C The following function inserts a node into a BST.-RECURSIVE algorithm. TREENODE *InsertNodeTree(TREENODE *Root, int Num ) { TREENODE * p; if( Root == NULL) p = MkTreeNode( Num ); Root= p; else if( root->Num > p->Name) Root->left = MkTree( root->left, Num); else Root->right = MkTree( root->right, Num ); return Root; } TRAVERSALS of the BST: /*------------PreOrder: to display the contents of the tree in preoder -----------------------*/ void PreOrder ( TREENODE *Root) { if(Root){ printf("%s\n",Root->Name); PreOrder( Root->left); PreOrder( Root->right); } } //-----------------------------------------------------------------------------void InOrder ( TREENODE *Root) { if(Root){ InOrder( Root->left); printf("%s\n",Root->Name); InOrder( Root->right); } } //-----------------------------------------------------------------void PostOrder ( TREENODE *Root) { if(Root){ PostOrder( Root->left); PostOrder( Root->right); printf("%s\n",Root->Name); } } 39 St Joseph’s College ( Autonomous ) Data Structures Using C The main binary-in-thread tree is implemented using the following routine. Care is taken to see that the right child is attached properly, at the desired location. QUEUE A QUEUE is another form of a restricted access list. In contrast to a stack in which both insertions and deletions are performed at the same end, a queue restricts all insertions to one end while all deletions are made at the other. The result is analogous to pushing marbles through a pipe. The marbles are dropped into one end and exit from the other end in the same order in which they entered. This type of data structure is considered to be a first-in-first-out ( FIFO ) type storage system. The end at which entries are removed is called the head ( Front )( or sometime the front ) of the queue. The end of the queue at which new entries are added is called tail ( or Rear ). Operations on a queue: The following operations are associated with the queue. 1. Create a queue 2. Check whether a queue is empty 3. Check whether a queue is full. 4. Add an item at the rear queue. ( enqueue ) 5. Remove an item from front of queue ( dequeue ) 6. Read the front of queue. 7. Print the entire queue We may define a Queue as given below: typedef struct QueueType{ Int Data[SIZE]; Int Front, Rear; } QUEUENODE;; As an example of this representation consider a queue of size 6. We assume that the queue is initially empty. It is required to insert element RED, BLACK and BLUE, followed by delete RED and BLACK and insert GREEN, WHITE and YELLOW. The following fig. Gives the trace of the queue contents for this sequence. RED RED BLACK BLACK BLUE BLUE BLUE GREEN BLUE GREEN WHITE BLUE GREEN WHITE 40 YELLOW St Joseph’s College ( Autonomous ) Data Structures Using C Now if we try to insert ORANGE, an overflow occurs even though the first two cells are free. To avoid this drawback, we can arrange these elements in a circular fashion with QUEUE[0] following QUEUE[N]. It is then called a circular array representation. We may represent the circular queue as given below. CIRCULAR QUEUE ( Array Implementation ) Rear 35 20 30 Front 12 Let A[5] be an array. We initialize the Front and the Rear to -1, indicating that the Circular List is EMPTY. Rear = Front = -1 To insert an element (number) into the CIRCULAR QUEUE, always the Rear is INCREMENTED first. To increment the Rear we use the following formula. Rear = (Rear+1)%SIZE And then the new item is inserted at A[Rear] CASE I: The list is empty. Then make Rear = Front = 0 and insert the number at A[Rear]. if( Rear == -1){ Rear = Front = 0; A[Rear]= Num; return; } CASE II: ( The List is not empty ) Increment the Rear index. If Rear becomes equal to Front, the QUEUE is full. if( Front == (Rear+1)%SIZE ){ Printf(“ QUEUE is full”); Return; } Otherwise, insert the new element into the array at A[Rear] Rear = (Rear+1)%SIZE; A[Rear ]= Num; 41 St Joseph’s College ( Autonomous ) Data Structures Using C CIRCULAR QUEUE: Linked List Implementation: 42 St Joseph’s College ( Autonomous ) Data Structures Using C Here you have a pictorial representation of a CIRCULAR QUEUE. You notice that the Rear node is linked to the Front node, thus making it a circular Queue. Our first task is to create a new data type to represent the node of the circular linked list which contains a data item and a link to the next node. We shall represent the node of the Circular Queue as: typedef struct CirQueType{ int Num; struct CirQueType * Next; } CIRQUEUENODE ; Now let us write a function sub program to create a node of the Circular Queue: CIRQUEUENODE *MakeCirQueueNode( int Num) { CIRQUEUENODE *NewNode; NewNode = ( CIRQUEUENODE *)malloc( sizeof(CIRQUEUENODE)); NewNode→Num = Num; NewNode→Next = NULL; } Now the question comes as to how to insert a node into the Circular Queue. We create tow GLOBAL POINTER VARIABLES Front and Rear of the type CIRQUEUENODE; QUEUENODE *Front, *Rear; We initialize them to NULL to indicate that the Queue is EMPTY. CASE I ( The Queue is empty) First we check whether the Queue is empty. If it is empty, then make the incoming node the Front and Rear of the queue. NewNode = MakeCirQueueNode( Num) if( Rear == NULL){ Front = Rear = NewNode; return; } CASE II: Queue if not empty If the Queue exists and if the capacity is not full, then attach the NewNode to the end of the Rear Node, and make that node the Rear of the queue. Rear→Next = NewNode; Rear = NewNode; Now link the new Rear node to the Front as: Rear→Next = Front; Complete code for inserting the new node is given below. 43 St Joseph’s College ( Autonomous ) Data Structures Using C DELETING A NODE from the Circular Queue ( Dequeue ) In a Queue, since it is FIFO Abstract Data the Front node is based on Type, always deleted. To do this , first the data item on the Front Node is assigned to a variable. Then Front→Next tis made the Front Node. And then, the Rear→Next is assigned the new address of the Front Node as shown below. 44 St Joseph’s College ( Autonomous ) Data Structures Using C PRIORITY QUEUE: Many applications involving queues require priority queues rather than the simple FIFO strategy. A priority queue is a data structure with only two operations: Insert an item and remove the item having the largest ( or smallest ) key. If items have equal keys, then the usual rule is that the first item inserted should be removed first. Each queue element has an associated priority value and the elements are served on a priority basis instead of using the order of arrival. For elements of same priority, the FIFO order is used. For example, in a multi-user system, there will be a several programs competing for use of the central processor at one time. The programs have a priority value associated to them and are held in a priority queue. The program with the highest priority is given first use of the central processor. Scheduling of jobs within a time-sharing system is another application of queues.In such a system many users may request processing at a time, and computer time is divided among these requests. The simplest approach sets up one queue that stores all requests for processing. Computer processes the request at the front of the queue and finishes it before starting on the next. Same approach is also used when several users want to use the same output device, say a printer. In a time-sharing system, another common approach is used to process a job only for a specified maximum length of time. If the program uis fully processed within that time, then the computer goes on to the next process. If the program is not completely processed within the specified time, the intermediate values are stored and the remaining art of the program is put back on the queue. Dequeue is a list in which additions and deletions can be made at either the head or the tail, but not anywhere in the list. Computer Exercise: Write functions in C to remove items form the front and rear of a Dequeue. 45 St Joseph’s College ( Autonomous ) Data Structures Using C 46