Sie sind auf Seite 1von 88
pata Structures “Fo about te diferent ypes of finked sts * fom about operations on faked fists [pew about applications of linked lists + gga wih sol referential structures 1 Cemprchondl the ad T eprent icks nnd ques using linked sts understand infix, prefix, and posttix expressions e readers will be able to ages and disadvantages of linked lists 41.4 Introduction = ‘Arrays are probably the most common data structures used to store large numbers of homogeneous data elements, Arrays are easy to declare and the array elements can also be accessed by the index numbers easily by using the symbols [ and }. Therefore, arrays are used in most languages including C, However, arrays have some disadvantages also and they are as follows. . Fixed size The size of an array is fixed. With a little extra effort, by dynamically allocating an array in the heap, specifying the size of the array can be deferred until the array is created at runtime, but after that it emains fixed. Arrays can be dynamically recized with the function realloc (), but that requires some programming effor. Wastages of space If the number of elements in an array is less that the size of the array, which is fixed in advance, then it leads to wastage of space, Sequemial storage Aw array allocates memory forall its elements chunked together se one block of memory. For arrays, contiguous space is required. If the program quer needs to process larger number of elements, the code will erash. Possibility of overftow If the program ever needs fo process more than the size, there is a possibility af overflow and the code breaks. Digheniry in insertion and deteion Inserting new elements at the front cannot be Cineleniy done because existing elements need 10 be sifted to make room, Similar A coo tor deletion alps Toeretote, Nese-opesallods required Joc ot mateento data, thereby leading to an inefficient and time-consuming algorithm. In case of deletion, te space of the deleted element cannot be freed. 598 « Computer Programming and Data Structures An appropriate solution to these problems is the linked dist, which, at some cost in memory space. permits lists to be constructed and modified easily. A linked list is an ordered collection of elements, where each clement hay at least one painter for pointing to the next element of the list and at least one valve, Such an clement is known as the node of a linked list, The singly linked list is the most basie of all the linked data structures. Both the array and the linked list are alternative implementation options for a sequence which is a collection of items with a defined order. Table 11.1 shows a comparison between these two implementations. Table 11.1 Comparisons between Linked Lists and Arrays Feature Linked list Amy Memory allocation Accessing items - Expressing ordar of items Eticioney of operation: Programming Noovertlowis possibio. All memory offered for an application available. ‘The links need additional space. Only sequential searchis possible. possible. No order is maintained since nodes may nt be storedat continuous ‘memory locations. Insertions and deletions are etlective, regardless of the pesilion they are insenedin Needs abit of experts. ‘All memory must be allocated before use. The memory space allocated can can be exhausted or left unused. Random access is possible, when the order number is known. Tha location in memory indicates the ‘order number of item, Many data movements are neededin insertions andin deletions of items. Very easy There are several variants of linked lists. These are as follow Singly linked list Circular Finked list Doubly linked list Doubly circular linked list The simplest kind of linked list is a singly linked list, which has one link ‘Per node. The link is nothing but a pointer. This link points to the next node in the list, or to a NULL value or empty list if it is the final node. A more advanced linked list is the doubly linked list or two-way linked list. Each node has two links: one points to the previous node, or points to a NULL value or empty list if it is the first node: and the other points to the next node, or points 10 a NULL value or empty list if it is the final node. In a singly circularly linked list, each node has one link, similar to an ordinary singly linked list, except that the next link of the last node Points back to the first node. It is usual to retain a external pointer pointing to the last element in a singly circularly linked list, as this allows quick insertion atthe beginning, and also allows access to the first node through the last node's next. pointer. In a doubly circularly tinked tst, each node has two links. similar to a doubly linked list except that the previous link of the first node points to the last node and the next link of the last node points (o the first node. As in a doubly linked list, insertions and removals can be done at any point with access to any nearby node. Linked lists have their strengths and weaknesses, but they happen to be strong where arrays are weak, All the features of arrays follow from the strategy of allocating the memory rr Data Structures F 599 all its elements i tos ear Sen eke memory. Linked lists use an entirely differen statety A later, s alloca ‘ehen necessary. te memory for each element separately and only ks and queues are a sel rokd IRL Int petra data types. They can be implemented using either a linear TAR ln this chapter, we will real about what these data structures acta eae cicand and operations associated with them, We will also learn how we can S and queue using arrays as well as linked lists > The first step in designing a data structure is to develop a mathematical model for the data to be stored in the data structure. The next step is to decide which methods we need to access and modify the data, A mathematical model together with methods to access and modify it forms what we call an abstract data type (ADT). ‘An ADT completely determines the functionality of a data structure, but it does not yet specify anything abou! how the data described by the mathematical model are organized in computer memory. and which algorithms are used to implement the methods. A data structure realizing, of implementing, an ADT consists collections of variables, which may be connected in various ways, for storing the data and algorithms implementing the methods of the ADT. Therefore, an ADT is a collection of data and a set of operations on the data that does not specify how the data is stored or how the operations accomplish their functions. An ADT is implemented using a data structure within some programming language, but the data struc: ture is not a part of the ADT. Very few programming languages have the ability to imple- ment abstract data types properly. The ADT can be used in software design without knowing how it will be implemented, ADTs and algorithms are the abstract tools that one uses for designing software, while data structures and other code represent the implementation of the finished product. Examples of abstract data types are lists, stacks, queues, and trees. ‘An ADT is characterized by the following properties: 1. It exports a type. 2. Itexports a set of operations. 3. Operations of the interface are ( This set is called an interface. the one and only access mechanism to the type's data structure. 4. Axioms and preconditions define the application domain of the type. itis actually the first stage of defining the problem so that we know what it does, but not necessarily how it will do it, The separation of data structures and operations and the con- straints to only access the data structure via a well-defined interface allows us to choose data structures appropriate for the application environment. ; Real provramming languages are free to choose an arbitrary implementation for an ADT. For example, they might implement the operation ‘add withthe infix operator ‘+, leading to a more intuitive look for addition of integers. The proper implementation of an abstract datatype should be (i) modutar so that different ADTs can be compiled separately: (ti) encapsulated so that all implementation details are hidden from the user (information hidis ing) and cannot be altered by the user. This is to ensure that the only way the user can access OF imanipulate the data is through the specified operations. 600 « Computer Programming and Data Structures ‘The benefits of using properly implemented abstract data types are: © Precise specification + Modularity © Information hiding * Simplicity * Integrity + Implementation independence A stack is an ADT for storing « collection of elements that supports the following methods: © push(e): Insert clement ¢ (at the *top" of the stack). . *# pop( ): Remove the most recently inserted element (the element on “top” of the stack) and return it; an error accurs if the stack is emply # isEmpty(): Rem TRUE if the stack is empty and FALSE otherwise The two principal ways of realizing the stack ADT are by data structures built on arrays oF linked lists, We will study these in the following sections. 41.3 Singly Linked List = A singly linked list is simply a sequence of dynamically allocated objects, each of which refers 10 its successor in the list. It allocates space for each element separately in its own block of memory called a finked list element or node. Each node contains (wo fields: a dara field to store whatever data type the list holds and a next field, which is a pointer, used to hold the address of the next node. The next field is used to link one node to the next node The beginning of the linked list is stored in a pointer termed as head which points to the first node. The first node contains a pointer to the second node. The second node contains a pointer 10 the third node, and so un, The last node in the list has its next field set to NULL. to mark the end of the list. No matter how many nodes get added to the list, head will always be the first node in the linked list. The empty list Initially the pointer head is initialized as NULL indicating the empty list, i.e. the list with no node. A linked list is represented pictorially as shown in Fig. U1.1. Read Fig. 11.1 Representation of a Singly Linked List is an ordered collection of elements called nodes cach of Observe that the linked |i which contains two items of information: a data element of the list and a link, ic., a pointer that indicates the location of the node containing the successor of this list clement which is a node. In Fig. 11.1, arrows represent the links. The data part of each node consists of whatever data type the list holds and the next part contains the pointer to the next node. The grounded Data Structures > 604 (a) head} 3, ) aS |) OR-cG-oR-ca, JO o-oo sentine! (9) Cran —— Fig, 11.2 Variations of Singly Linked Lists earth indicates NULL, Figure 11.2 shows several of the most commonly used singly linked list variants. The basic singly linked list is shown in Fig. 11.2(a). Each node of the list contains a pointer to its successor: the last node contains a null pointer. A pointer to the first node of the , labeled head in the figure is used to keep track of the list The basic singly linked list is inefficient in cases where nodes are required to be added at both ends of the list. While it is easy to add nodes at the head of the list, to add nodes at the other end, called the raif, one necds to locate the last element, If the basic singly linked list is used, the entire list needs to be traversed in order to find its tail. Figure 11.2(b) shows a way by which adding nodes to the tail of a list is more efficient. The solution is to keep a second pointer, tail, which points to the last element of the list. Of course, such efficiency comes at the cost of the additional space used to store the fai pointer. The singly linked lists [see Fig. 11.2(c) and (d)] illustrate two common programming tricks. The list in Fig. 11.2(c) has an extra node at the head of the list called a sentinel. This element is never used to store data but it should be present in the linked list 10 store the address of the first node. The principal advantage of using a sentinel is that it simplifies the programming of certain operations, c.g.. since there is always a sentinel standing guard, we never need to modify the head pointer. Of course. the disadvantage of a sentinel, such as that shown in Fig. 11.2(c), is that extra space is required, and the sentinel needs to be created when the list is initialized. The list in Fig, 11.2(c) is also a circularly linked list, Instead of using a NULL pointer to delimit the cnd of the list, the pointer in the last element points to the sentinel, The advantage of this programming trick is that insertion at the head of the list, insertion at the tail of the list, and insertion at an arbitrary position of the list are all identical oper: Figure 11.2(d) shows a variation of a singly linked list using a sentinel in which instead of keeping a pointer to the sentinel, the sentinel itself serves as the handle for the list. This. Variant eliminates the need to allocate storage for the sentinel separately. OF course, it is also possible to create a circular singly linked list that does not use a sentinel. Figure 11.2(e) shows a variation in which a single pointer is used to keep track of the list, but this time the pointer, tai, points to the last element of the list. Since the list is 802 4 Computer Programming and Data Structures (a) [head} head} © Prat © [ea —-cB) sentinel (©) [[head ‘sentinel ) (ay Fig. 11.3 Empty Singly Linked Lists circular in this ease, the first element follows the last clement of the list Therefore, it is relatively simple to insert at the head or at the tail of this, fist. This variation minimizes the storage required, at the expense of a Tittle extra time for certain operations. Figure 11.3 illustrates how the empty list (i.e. the list containing ng list elements) is represented for each of the variations given in Fig. 11.2, Notice that the sentinel is always present in those list variants, which use it. On the other hand, in the list variants, which do not use a sentinel, null ¢ the emply list. pointers are used to indi | Here in the implementation of a singly linked list only head is considered, A node of the singly linked list can be represented in C using the function struct as follows: struct node i dataz The first field is an integer named data and the second is a pointer to the next node in the list as shown in Fig. 11.1. Such structures that contain a pointer that points to the same structure type are called self-referential structures. Therefore, a linked list is an ordered collection of structures connected by logical links that are stored as a part of data in the structure itself. The link is in the form of a pointer to another structure of the same type. In this case, note that the data field is an integer but it could be any complex data type if required. In general, a node can be represented in the following manner: Le The structure may contain more than one item with different data types. the items must be a pointer to the tag-name. Example: tag-nane| . However, one of node char name{NAMELENJ; /+ data: name */ int y struct nede tnexts cr 7+ dati year */ f+ pointer to the next node +/ ‘An example of a more complex node is as follows: Data part: typedef struct 4 char codat®}; /* course code ” Data Structures » 603 char name(2612/+ course name int credits: /* course cronit a jactures: /+ ji u 1 #7" no. of tecture hours -/ labs; /* no. of Lab hours) 1 courses Node: struct node \ course data: 7* course information “v struct node ‘nent: /* pointer to the next node « Singly linked list containing any ofthe nodes declared, as above, is known as a homogeneous Tinked list as it contains similar types of nodes. To represent non-homogeneous list (those which contain nodes of different types), a union may be used, For instance, consider the following declaration of a node: struct nedo ‘ int etype: ( int ival, float fvat char ‘sval; 1 struct node ‘next; It declares a node whose clements may be either integer, or floating point numbers or string depending on the corresponding et ype. Since a union is always large enough to hold its largest component, the sizeof and malloc () functions can be applied to allocate storage space for the node, Here is a simple program, which uses pointer operations to build the singly linked list containing three nodes which have the values 1, 2, and 3 in the data field of the nodes respectively and displays it Hincluge Minclude struct node ' int datas struct node *nexts M = Void makelist (struct node * void display(struct node *); int main|} ' Struct nodo ‘heads head=NULL? 604 < Computer Programming and Data Structures cate 3 nodes in first s(struct node *)ma 1 second (struct node *)malloc(sizeof (struct node) ) i ied =(steuct node *)mal of (struct node) )s setup first node * outa Analysis of the above program To create the linked list, in the function makelist (}, the following three steps are used. 1. Allocate the new node in the heap and set its data part to whatever needs to be stored. 2. Set the next pointer of the current node to point to the next node of the list. This is actually just a pointer assignment. Note that assigning one pointer to another pointer makes them point to the same thing. 3. Store the address of the first node in head, In the function display (), a frequently used technique in linked list code is to iterate 2 pointer over all the nodes in a list. Traversing a linked list starts at the first node and cach node in succession is examined until the last node has been processed. In the function display ()., the pointer head is copied into a local variable p.which then iterates throug? the list. The end of the list is tested with p!=NULL. The statement p=p->next. advances the Data ttuctues > 605 Jocal pointer p (0 the next node in | using for, Which makes the initial for (mpl he list. Alternately, Wzation, test, and pr IP=P next) | sume tltht prefer to write he loop Het tpsdating were aptinnized 4 88 Beginners are alten confused aby : eens ae fen ntl bout how the statement pap-onext makes p polit to the Baked Hs sowing ove aes pin pp ae Heth am como, Sass ® P iS pointing to the first i st nade (nee Hip. bt), 100 10 14.4 Actual Reprosentation of a SLL in Memory Fig. Instead of showing the links to the next node, Fig, 114 shows the address of the next node in the next part of each node. When the statement p=p-» next is executed, the right hand side of this expression yields 400, This adress is now stored in p. Av a result, p StAM18 pointing 10 the node present at ackdress 400, In effect, the statement his shifted p so that it has started pointing to the next node in the linked list, Figure 11,5 show a graphic representation of a linked list traversal. Fig, 14.5 Traversal of a Singly Linked List tobe observed that in the function makeli st () the formal argument is a pointer to pointer of type struct node where éhead is passed to this function. On the other hand, in the function display (), only head is passed as parameter, so the formal argument is a pointer oftype struct node, InC, changes 10 local parameters are never reflected back in the caller's memory, It is to be noted that the function makel ist (1 is needed to change some variables of the caller's memory, namely the head variable, The traditional method to allow a function to change its caller's memory is to pass a pointer to the caller's memory instead of a copy. So in C, to change an int in the caller, pass an tint *” instead. To chunge aT, pass a +. where 7 is any data type. Therefore, if a value struct node * isto be changed, itis needed to passed as struct node *™ instead. The type of the head pointer is “pointer to astruct node”, In order to change that pointer, we need to pass a pointer to it, which will be a “poi toa struct node”. Ineead of setingvela Snake ist(struct node *), itis needed to define void makelist (struct node **). The first form passes a copy of the head pointer. The second, correct form passes a pointer to the head pointer. In the code, Ehead is to be used ction and ** should be used in the parameter of the 8 actual parameter in the calling fun ; called function, Incide makelist (), the pointer to the head pointer is named h. 606 < Computer Programming and Data Structures Figure 11.6 shows the memory diagram just before the first call o makelist () exits, The original value of the head pointer is in dotted line. Notice how the h parameter inside makelist () points back to the real head pointer back in makelist (). makelist() uses +h to access and change the real head pointer. STACK] HEAP In makelist () itis pointer to the “head of the linked list back in the caller's memory space. Fig. 11.6 Memory Diagram for Pointer to a Pointer to head ‘The general rule is that if there is a statement in the function that modifies the content of the pointer head, then the address of the pointer head must be passed to that function, This program is all right if the number of nodes is too few. It is not worthwhile to declare a Pointer for each node. A better implementation is given below where the same pointer is used to create nodes. To make a list, the append() function may be called repeatedly. void append{ateuct node **h} t struct nede *p, ‘tmps /* Creation of new node */ P w{struct node *)malloc(sizeof (struct node) ); LE (p==NULL) i printf£("\n Memory allocation unsuccesatul.."); return: ) print€(" \n Enter dataza"}; scant ("8d", ép->data) : poonext-=NULL: /* appending the newly created node in an empty Linked list */ if Ch=-NULL) t ohep: return; ) /* Traversal of list te find out the last node */ ump-th: while (tmp->next !=NULL) Data Structures > 607 tmpetmp= next, /* appantina the nowly created node aftar tha 1 ‘The append () function has to deal with two situations: Adding . xe Lo an empty list Second: Aiding the node to the end of the linked list {the linked list is empty then the pointer head will contain ULL, Hence space for the new node using malloc (). Then the data and the next field of this nod Lastly, head is mule to point w this node, since the first node has been ated to the an head must always point to the first node, Note that *h is nothing but equal to head. If the list is not empty, then one has to traverse upto the last node and append the new node, address of which is stored in p, at the end of the last node. Traversal of a singly linked list has been discussed earlicr. However, for the convenience of readers, it has been explained again. A pointer of type steuct. node. tmp. is made to point to the first node in the linked Tist through the statement allocated tmp-*hs Then with tmp, the entire linked list whLlo(tmp=snext {=NULL) traversed using the statements: tnp-tep->next; Each time tmp points to the next node in the list through the while loop using the statement tmp=tmp->next. When tmp reaches the last node, the condition tmp->next != NULL would fail. The position of the pointer after traversing the linked list is shown in Fig. 11.7. Fig. 11.7 Appending a Node into a Singly Linked List Now the previous last nade has to be connected to this new last node, tmp points to the previous node and p points to the new last node They are connected through the statement tmpeonaxt = pz Compiting all the steps, the algorithm for appending a node in a singly linked list is as follows: 1. Whether the linked list is empty or not. one necds to create a new node and fill it with data, ‘ in a poi Trike address of the newly created node is stored in a pointer, say p, then set the next field of this node to NULL: because, the newly added node is always the last node, — 3. It the linked Hist is empty, make head point to p. If the linked list is not empty, in that ease, the current last node in the linked fist (not p) is no longer the last one. So, the Inst node should be linked to p by assigning the next field ofthe last node to p. 610 Computer Programming and Data Structures The order in which the two pointer assignments are made is important. If the order of the assignment statements is reversed, then the value of tmp->next would be lost before itis used and there would be no way to attach the new node (pointed by p) to the remainder of the list. This code can now be built into a function insaft () to insert a new node after a particular node in a singly linked list. vold ineaftteteuct node **h) 4 struct node ‘py ttapy int ke ifn t ULL} Print€("\n Linked List is EMPTY..void INSERT returns new node ja to be inserted iy) for(tmp=*h; tmp!sNULL 66 tmp=>d: Af (Emp>-NULL) printf (*\n NODE DOES NOT EXIST): This loop moves tmp to the target node if (pe=NULL) ‘ print€("\n Momory allocation un: return; ) printt(" \n Enter data acont ("ed", sp-pdata Pronent=trp=snoxt; node *)malloc{sizoof (struc dey) tepeonext=pe , The recursive version of the preceding function is as follows. In this version, it is needed 0 pass a value (0 the data field of the node afier which the new node has to be inserted, void ingatt (struct node ‘+h, int k) 1 truct node +p) LEC heetLL) i print£("\n NODE DCES NOT EXIST or \ Linked List 1a BAFTY..void INSERTION"); returnt 1 alae if ((h)->dataeek) 1 P (struct node *)malloc(sizeof (struct nodo)) EEE Data Structures > 611 printf(* \n Enter datas); ne (TEA, Soeodata) Prenext=(+h) ->nexty (th) ->nextep; return: else Ansatt(4(+h)->noxt, ke ) Note that in the function insaft (j, there would be no change not required to pass Ehead as an actual parameter to the function. | with fh and the formal parameter would be struct. node *h. This version of the insaft (} function. Consider that the node, after which the insertion of a new node is to be carried out, is specified by giving its position with the first node at position 1, second node at position 2, next node at position 3, and so on. Like done earlier, start by pointing the pointer variable h to the head of the singly linked list, A loop then moves h forward to the correct node as shown in the program. Therefore. h is naw pointing to the node after which the new node has to be inserted. ‘The rest is the same as before. Follow the definition of the function, which is given as follows: head. Therefore, it is fe to replace all *h s illustrated in the next ft_ath {struct node *h) void ins int position, i, printg("\n Enter the position after which new node \ is to ba inserted :"|+ scanf ("d", position) «for (i-ish!-HULL 6s icpoaitions ++) heh=>nexts if |he=NULL) printé(* There are less than $d nodes \ in the List", position) s else 1 p slatruct node *}malloc(sizeof (struct node} ) if (p=*NULL) prints {*\n Memory allocation unsuccessfull.."l1 return; ' 612. ¢ Computer Programming and Data Structures print£(" \n Enter data: peant ("td",spe>daca) ; pronext eh->next: h>next-py 1 Us recursive version is as follows: (struct node *hyint position) void insaft_ 1 sie int Let: struct node ‘ps AE(heeNULL 66 1 ( printf(\n Linked Liat is EMPTY. .vold INSERTION"); return: i else if (he=NULL 6% 4>1) printf (” There are less than $d nodes in the else iffiseposition) i p s[struct node *}malloc(sizeof(struct noce))+ i £(p--NULL) 1 printf(*\n Menory allocaticn unsuccessfull..)7 return t printé(" \n Enter data: ")+ aeant ("44", 6p->data); poonexceh->next: ho>next-p? ' else ( insaft_nth{h->next,poaition): ) insertion of a node before a specified node A function insbef () that inserts a new node can be defined as follows. void insbef(struct node *+n) *p,*tmp, ‘prev: neds o List is EMPTY..void INSERTION“); Data Structures » 613 do Sa te be inmerted i711 St (pesttty Printt("\n Memory alte returng printf (" \n Enter data: +) ant ("4", Gpeadatal , poonegteth: Shep: 1 temps Ch) -2next specially prove ecked as tha first whilettmp!=MULL) ‘ LE (tmpo>dataeek) break: else 1 proverrpr tmpetmp->noxts ' ) Af (erpeeMULL) 1 printf (*\n NODE DOES NOT EXIST): else { p cfercuct node *)mallaeta!zeofletruct node) Lf (perNutt) ‘ prinet (*\n Memory altecat ice unsuccessful.) 614 4 Computer Programming and Data Structures To insert a node before a particular node that holds a specific value in its data field, the ‘node has to be located. Since the singly linked list is unidirectional, it is not possible to move backwards to find its predecessor so that the new node can be inserted. The predecessor of a Particular node might be found if one traverses the list as long as the next field of a node becomes cqual to that node. However, the best way is 10 usc a pointer, prev which points to the preceding node that is pointed to by another pointer tmp. The pointer trap is used to scan the Tist using a loop. Its initialized to the node next to the first node (this is discussed in this section tater on). It is advanced to the nex! node using the statement tmp=tmp->next, Before this assignment statement, tmp is assigned to prev So that at any moment of time the Current node (pointed by tmp) and its predecessor (pointed by prev) can be accessed, If tmp->data is equal to the value of »: (a variable used to specify the value of the node to be Tocated), then the new node is inserted between the nodes pointed by prev and tmp respectively. The insertion scheme is depicted in Fig. 11.9. head ae tnpy ‘Ay Z xo qe Fig. 11.9 Insertion of a Node before a Particular Node in a Singly Linked List The pointer p is pointing to the newly created node that has to be inserted, Now, the next. field of the node pointed to by p should point to the node pointed to by tmp, and the nexe field of the node pointed to by peev should point to the new node pointed by p. The following wo program statements accomplish this, Fonoxt=tmp; fen proyeonextep: w Insertion before the first node pointed to by head (in the function it is *h) of a singly linked list is treated specially because such insertion implies modification to the pointer head. Figure 11.10 shows this insertion scheme. head P «sy t++{_Teh, ‘el Fig. 11.10 Insertion of a Node at the Beginning of a Singly Linked List 4s clear that the next part of the new node should point to the node that is pointed to by {in the function it is +n) and this newly added node hecomes the starting node of the head points to it. Therefore, the following two pointer assignments are required. Data Structures > 615 hewtene ‘ 1 is required to modify the content of the pointer head. The actual argument of the function insbef () would be Gheact and the formal parameter would he st ruct nod If the node, before which a new node has to be inserted. is specified by giving its postion, the insertion algonthm remains the same, Implementation of the same is left to the readers. 11.3.2 Deletion of a Node from a Singly Linked List Suppose, one wants to delete a nade from a singly linked list that holds @ particular value in its data field. The node hay to be located first and then detached from the list by linking the predecessor of the node (0 its successor. Now the memory space fur this node hay 10 be disposed off by calling the function £rce(). As discussed earlier. a singly linked list is nidirectional, Two pointers tmp and prev are initialized in the loop so that they point to the current node being scanned and its predecessor respectively. At each iteration. the data field of the current node (pointed to by trp) is investigated and then is advanced to the next node through the call trp=tmp->next. Obviously, before advancing to the next node, trp has to be assigned to prev. Removing the first node poimed wo by nead should be treated specially just like an insertion at the beginning. The rest of the scheme is outlined in Fig. 11.11 we Tete CE, my 0) headeneadonert: freettrels (a) Deletion of the First Node of a Singly Linked List head wp 4 af an prevernextetepernext# 7) Free(tmp)s (b) Deletion of an Intermediate Node of 2 Singly Linked List Fig. 11.11 Deletion of « Node from a Singly Linked List “The function for the deletion af a node from a singly linked list is as follows. woid delnode(etruct node *°h) 818 4 Computer Programming and Data Structures printf ("\n Linked List 1s EMPTY..¥ f* doletion at tho begining */ LEC (th) =>datasee t npothy she(th)->next: frea(tmp) returns , tmp- +h) ->noxts preveth? while (tmp tenULL) ‘ Af (tmp-odatank) break: alee prevetmp, impetmp=>nex: print£(*\n NODE DSES NOT EXIST"); ' alse { prov—>next=tmp->next frea(tmp); ) ‘The recursive version of this function needs an cxtra parameter &, which is the data value of the node to be deleted. Void dolnede( struct node { Po steuct nods ‘next_n: int ky SifC ch een LL) Print€("\n Linked List is EMPTY or NOCE doos not \ exist..vold DELETION") ; Data Structures > 617 , Ane Ch)spdata = ( next (hi onexts free( this /* if the nodes were mallccted + 1 delnedot &( (h)~ ne ' __ Readers are advised to create a program for the deletion of the nth node from 3 singly linked list as an exercise. 41.3.3 Sorting a Singly Linked List ‘The soning of a singly linked list means arranging the nodes of the list in ascending values held in the data field. This ean be accomplished in two ways: firstly arranging the nodes by physically disconnecting the links, and secondly, ordering the nodes by exchanging the values stored in the data fields of the nodes. The second method is considered here. The sorting method used here is bubble son. In bubble sort, the loaps used are as follows: for(ieDsicneLrert) fl for(J0¢5eneb-2sjr) Here n is the number of nodes of the singly linked list, which can be computed using a function named count (). It uses the general traversal technique to obtain the number of nodes in a list. Two consecutive nodes are considered and if the value of the data field of, the first is greater than that of the second, then the values are swapped. However, the problem is that every iteration associated with 3 in the outer loop needs to start from the first node of the singly linked list. So, before entering the 3 loop. the temporary pointer used for the travereal fin the function it is *p) must be set to point to the first node by’ the assignment statement p2head. In the inner loop, the statement ++ docs not cause the pointer p to move to the next node so that the next two nodes of the list can be examined. So. in the inner Joop. 10 advance 1o the next node, the statement p=p=7next must be included. The definition of he function set [) that docs the described operation is given here. In this function, a variable sorted is used to make the function more efficient by reducing the number of additional iterations, when the list has already been sorted. teuct node *h) void sort(s ( struct node * n=O, t, sorted 618 4 Computer Programming and Data Structures sorted=0; for({-0;ien-1 bk Isortedsi er) ( pens soutad=ts for (Jo0uJenatersje+) ( LE (p=>data> (p=rnext)->datal ( e>data; poodata=(p->noxt) ->datas {p->noxt)~>data-ty sortad=or ’ ao 1 Here is the definition of the function count (), which returns the number of nodes ina singly linked list. Iterative version Recursive function Int count (struct node *p) int count (struct node *p) ( 1 dnt tr Af (pe-NULL) for (1-01 p!-NULLip=p->next) return 0; ives else return return (1+count(p->next) i ’ ) 11.3.4 Destroying a Singly Linked List Destroying a singly linked list means deleting all the nodes of a singly linked list. The function destroy () removes all the nodes from a singly linked list and retums them to the heap. Herative version Recursive function vold dostroy(struct nodo *+h) vold destroy(struct node *th) t t struct node *q7 AE(*h=-NULL) if (ehtenuLL) ( t Printe("\n Linked List is expty"); — destroy(t (+h) ->next) 1 returns 3 fren(> We *heNULL Lo (+h! -NULL) To avoid dangling pointing jth) next; (ny; 2 Dete Structures » 619 note Be catetul while coding to delete all the nodes of a linked lis The following version of the ' preceding function is incorrect The reason is that after freeing p contains an address that has already been de-allocated; therefore the statement p=p->next; has no fruitful meaning. As a result the code may crash. To sum up a C program that can camry out any of the discussed operations on a singly linked list, with the help of all the C functions defined in this section, is given as follows. jo de nt data: void append(struct node **); void dispall(struct node *) AFTER A PARTICULAR NOCE “) BEFORE A PARTICULAR NOD 620 4 Computer Programming and Data Structures Liappend(shead)} 7 break? Ordispall (head) gbroake sate (head) grea ‘et (ahoad) breaks lelnada (shear sbeeaks rt [head) break; breake deat roy(shead! rt (0) prince (*HRONG CHOICE default , return OF 11.3.5 More Complex Operations on Singly Linked Lists Printing a Singly Linked List in Reverse Order To print the nodes of a linked list in the reverse order (without using an additional singly linked list, two loops are used in a nested fashion. Two pointers tmp and last are used tmp is used to traverse the list up to a point. First, the list is wraversed up to the last node, and then up to the second last node and so on. The pointer 1ast is used to point to the node al ends, That is, the list is scanned using tmp from the beginning of thelist until it aches the predecessor of the node that is pointed to by Last. Then last is updated by the value of tmp. This process continues till 1ast equals head (in the function it ish). erative version Recursive function void diepall(struct node *p} void dispall (struct node “p) d { struct nodo ‘tmp, ‘last; ift LE(pesIttt) returns retur: else ( lastenuLt; dispall (p->next): tmp=p: Printf("\ttd “,pepdata); while (ast !=p) ‘ b tap=pF 1 while (tre-rnext!=last} tmprtrp-onext; Print£("\t#d “,tep=>data) ; Jast-tre: fu the values of the data field of the nodes of a singly linked | {reverse order but the lst remains as it is. To physically reverse 2 sna) singly linked list) ie. the last nade becomes me M Data Structures > 621 axle, the second last node becomes the second node, and so on. In order tw reverse the entire List, reverse: all of other than the first node am then plug the first node at the end of the list Now, there are WO ways to reverse a linked hist. The first version is an iterative (non recursive) solution Here isa function that Gkes head of a singly hinked list as a parameter. reversey It, and returns a pointer to the beginning of the reversed ist. As the returned address is asuizned £0 Head again. it ty not required to pass the address of head to the function Function prototype declaration: Function calling statement: Fe cur = pHoxts ) while (cue t= NULL? geturn prov! 1 ‘The special case, where the linked list is empty (XULL, is handled first: the reverse of a MULL list is a NULL list, If the list is nat empty, the following three pointers are required: # pointer to the current node (the one Which needs its next field (0 be updated) pointer to the previous node (the one to which the current noe should point to) © pointer to the node next to the current node (to become the current after the current node gets its next field updated) Start with the first node being the current one and the previous node being NULL (since the first node becomes the last and points nowhere). At each iteration of the do-while loop. the next field of the current node is updated and the pointers are upkated. When the end of the list is reached and the loop stops: prev (which stores the previous value of cur) Points to what used to be the last node and is now the first, so it is returned. Here is a = provi scary 622 ¢ Computer Programming and Data Structures Lf (he>noxt == NULL) return by imp = reverso_List(h->nent) s (heonext)=>noxt = hi heonext = NULL} return trp: ) ‘The recursive function has two base cases. If the list is empty. it stays empty, and if the list isa single mode, it remains the same. These two base cases could be combined into one, returning h if either condition is true, Otherwise. one can use it as the general case, reverse_1ist() is recursively called by passing the list starting with the second node, considering the current node to be the first. Since the next field of the current node has not changed, and it used to point to the first node of the remaining list. it now points to the last node of the remaining list. That node (the one pointed to by the current node) is updated to Point to the current node, and the current node is updated to point nowhere (its next field becomes NULL). Copy a Singly Linked List A given singly linked list can be copied into another list by duplicating the values of each node. The following C program performs this task. Observe the function copy list () that takes the target list and the source list as parameters and uses a new logic for creating a singly linked list. Hincluda Finclude struct node t int dai struct node ‘next, uv vold appond(atruct node **); vold dispall(steuct node *); void copy list(struct node **, struct node +); int main() ‘ struct node ‘head, *ha; ("An CREATE THE FIRST LINKED LIST...\n"); "\n Do U add more noda(y/n}?.."); fstdin); Data Structures > 623 dispall head); By (4hd, head print£("\n PRIN printf ("\n The spall (ha)? return 0; 1 void appendistruct node + ‘ LE (+h=-NULL) { tho=/ Lec i Print#("\n Memory allocatio: return: h printé(" \n Enter dataz"): scant ("8d”, 4 (+h) =>data) (+h) -pnext NULL: 1 else append(4(*h)->next)s ruct node *)mall NULL} claizeof (struct noae)): ’ void dispall(struct nede *p) ‘ if (p=-NULL) ‘ prince (MULL): return: ' else i Frinte("d 7) peodarals Guspall (poner!) 1 vold eopy_List.arruct rede ttt, struct node +2) node LL, retars while ‘a! -NULLt 1 Le(treeNTL seuct nedeila starr node timadios(etzect 624 < Computer Programming and Data Structures else 1 tmpasnext =(struct nedo *)malloc(sizeof (struct nodel)+ tepetmp—noxt ’ trp->data-s->dataz ses-onext ' tep=>nexteNULL; ' The recursive version of the function copy_List () is as follows: void copy list(steuct node ++, ateuct node +2) t if tatenuLt t stelstruct node *)malloc(sizeof(atruct node))+ (1t}->dataes->datay (t} onext NULL; copy_lis= [é{(*t)=>next), a=>next ) Maintaining a Linked List in Ascending Order Let us ereate a singly linked list where every new node added to the linked list gets inserted at such a place that the linked list is always maintained in ascending order. The following version of the append) function illustrates the same, The trick followed here is that while traversing the linked list, the data part of the node to be inserted is compared with that of the current node and that of its subsequent one and accordingly inserted. vold appendistruct node *+hi ‘ struct nede “py “tmp; Pr(struct node *}malloc(sizeof (struct node); prAnte(" \n Enter data:™); scant ("8d", sp-adaca)s f* if list is empty or if new node is co be inserted beforo the first node */ Af (*h=-NULLD SEE ee Data Structures » 625 /* traverse the entire pode */ 1 cepetmp-onexts 41.4 Circular Linked Lists ==e2=essee= Although a singly linked list is a useful data structure, it has a major drawback. From a given node, say, pointed to by a pointer p, it is not possible to reach any of the nodes that precede the node which p is pointing to. To overcome this drawback, a small change is made to the structure of the singly linked list so that the next field of the last node is pointing to the first node rather than NULL. Such a linked list is called a circular linked list and is shown in Fig. 11.12. Lasinode bo Fig. 11.12 Circular Linked List it is possible to reach any node in the list cause by virtue of the ‘ode is also the last node and vice versa. Therefore, one useful convention is to let the extemal pointer of the circular linked lis, to). point 10 the last node and to allow the following node to be the first node. Another important point is that Tike the singly linked list, the null pointer represents sm cemply circular linked list. Following are the most common operations performed on circular linked lists: From Fig. 11.12, it is clear that in such a list, from a particular node. Note that there is no natural first or last node bi list being circular, the first n 626 < Computer Programming and Oata Structures #include dlib.h> Hinclude next: ay tail oo Ppomnext = an tail an Here is the function definition for appending a node into a circular linked list, written using the preceding steps: id append(struct node struct node *py ‘head? pr (struct node *)malloo(siz 1f(pe-NULL} ( print£("\n Merery allocation wl eof (struct node) ): nsuccesstul,.")4 return; ) printf{"\n ENTER THE DATA, peant(*kd”, sp->datalt Af (+t e=NULL) 628 < Computer Programming and Data Structures ( PE ponextett; head= (+t) -2nex:, [+t) nex podnexthead; *tepe ) Note that in the function the formal parameter ¢ is a pointer to the external pointer tai2 which is declared in main (). When a new node is inserted at the end of the list, the value of the tail should be updated through *¢ irrespective of whether the circular list is empty or not as the newly inserted node is now the last node. In Fig. 11.14, *t is not used for better interpretation. (18) Fig. 11.14 Appending a Node in a Non-empty Circular List 11.4.2 playing a Circular Linked List Traversing a circular list is slightly different from traversing a singly linked list because NULL is not encountered in the next fields for any node in a circular list. For traversing a circular list, one needs to save the address held in the next field of the node pointed to by tail. Let it be head. Now the node pointed to by head is the first node of the circular list. ‘Taking a copy of head in another pointer tmp, one has to traverse as long as tmp becomes equal to the saved pointer head. Therefore, itis sufficient to assign "tmp=>next’ to tre in ado...while loop as long as tmp is not equal to head. The implementation of this ‘operation in a circular linked list is as follows: vold dispall(struct node +t) 1 struct neda ‘tmp, thoad? Af{t=-NULL} ( peint€("\n LINKED LIST IS EMPTY\n") 7 returns 1 headetmp=t~>nexts print£(*\n" Data Structures » 629 do t printé(\t bf" tnpesdaray: tapetmp=>n Jwhdlettmpt=head) ¢ ) 41.4.3 Inserting a Node after a Specified Node “The next operation is the insertion of a node to the circular linked list, The nove. after which insertion takes place, is spevifiedcither by the value of the data field or hy the position in the list, assuming that the first node is at position one, Let the first case be considered. For illustration, consider the following circular linked list: ‘Assume thal tmp is a pointer pointing to the node after which the new node is to be jnserted. It has been discussed how the value of the pointer variable tmp is set so that it is, hfe to point to that node of the circular list. Mence, a new node pointed to by p has to be joserted after the node pointed to by tmp in a circular list, the last node of which is pointed to by taal in the function it is *t). This is depicted in Fig. 11.16. ps r-| +f > + Fig. 11.15 tnital Circular Linked List “ihe pe oH LOT Fig. 11.16 Insertion of a Node after a Particular Node Naturally, tnp->next and p->next ced to be updated so that after the insertion of the node, the circular linked list would be as shown in Fig. LL.17, ae (ROOK Fig. 11.17 Circular Linked List after Insertion of p should point to what tmp was pointing to before insertion That js, the next field the node that was being pointed to by p. and then the next. field of tmp should point 10 630 4 Computer Programming and Data Structures ponoxt = tre next 18) tmpsrnant © ps 113) Insertion after the node pointed to by tail (in the function it is *) of a circular Linked list is always treated specially because such an insertion implies modification to the pointer ti] which points to the last node of the list. This is illustrated in Fig. 11.18, Fig. 11.18 Insertion of a Node after the Last Node ‘The definition of the C function for implementing the insertion of a node after a specific node is as follows: ( int xy tound-0; | SE(+EHULL) | 1 | | | printf ("\n LINKED LIST IS EMPTY\n"), return: 1 printf (*ENTER THE VALUE OF THE NODE AFTER WHICH NEW NODE \ TO BE INSERTED ="): scant ("8d 6x) 2 EE((*t)s>datasexy *ymalloc(sizeof (struct nodel): Print£("\n Merory allocation unsuccessful...” roturn; | Print(*\nEMTER THE DATA: scant (*$d", sp=>data) + | po>noxt=( +2) -onext (ty -onext=ps step returns , tmp=|'t)-onexts while(tmp!=*t) 1 if (tmpe>datasmn) ‘ ‘ Data Structures » 634 pe(struct pedo + © *)mallocioize ce locteizeof (struct node); fl printe(\n ty retuen: 1 Printe(\nENTER THE para: BEANE IAA", bpaodata pa onexts femary allocation una stul.."): tmp-tmp=anexts ) if [found==0) printt(™\n 1 DE DOES NOT EXIST...°); It is left to the readers to follow the same scheme and develop a program far insertion after the nth node, 11.4.4 Inserting a Node before a Particular Node Like a singly linked list, a circular list is also unidirectional and moving backward is impossible because there is no direct link from a node to its predecessor. However, unlike the singly linked list. though it is cumbersome, the predecessor in a circular linked list can be found by moving through the list since the tai (in the function it is *t) is linked to the first node of the circular list. A node preceding a particular node. pointed to by p, can be found if one traverses the list as long as the next field of a node becomes equal to p. The best way is to keep a pointer, which stores the address of the previous node while moving to the next node. AS a result, at any moment, onc can access the current node as well as the previous node, Using this trick, if the desired node before which the new node is to be inserted is the first node, then it can be treated specially as the next field of the last node which will now point to the newly added node. This is illustrated in Fig. 11.19. tail Hi Cel (22) (23) 122) =onaxe=tail=>next? E (23) tai L->next-Pi Fig. 11.19 Inserting a Node Pointed to by p before the First Node 632 « Computer Programming and Data Structures, From the second node of the list, the logic to be followed is same as that followed in ease of singly linked lists, A new node pointed to by p is inserted before a node pointed to by tmp as illustrated in Fig. 11.20. Fig. 11.20 Inserting a Node before a Particular Node Here, prev is the pointer that is pointing to the node preceding the node pointed ta by tmp. The next field of p should point to trp and the next field of prev should point to P. That is, The C function for inserting a node before any node in a circular sbet (struct node +t) WHICH NEW NODE \ roturns print £(*\nENTER THE DAT! am data): i Data Structures » 633 Prev-head; tmprhoad=>next; while (tmp!=hoad) t if (tmp->datas-x) f pe(struct node -)malloc(sizeot (struct nede)); LE (pe=nULL) t Printe("\n Memory allocation unsuccassful..")+ return: ) Printf("\nENTER THE DATA: —“); seanf ("td", sp=>data) z prov->next-p: po>nextetmps found=1; breaks ) else ‘ prevetmp: tmpetmp= next; } 1 Lf (found==0) n NODE DOES NOT EXIST...")¢ printt( 1 11.4.5 Deleting a Node The general logic to delete a particular node pointed to by p is that the preceding node should be linked to the successor of p and then the memory space is to be de-allocated using a call to free (p). This scheme is illustrated in Fig. 11.21. (OHO, Fig. 11.21 Deletion of a Node from a Circular Linked List “The predecessor node can be found using two pointers tmp and prev, which are initialized so that they point to the current node and its predecessor respectively. These are used in a loop where tmp is used to scan the list and for each iteration: itis advanced to the next node using the statement tmp=tmp-2next. Obviously, before advancing tmp, the address contained ini is assigned to prev so that it can always point to the previous node of the current node pointed to by tmp. A number of special cases have 10 be considered here. 634 < Computer Programming and Data Structures Case 1; Deletion of the first node should be treated specially like insertion of a node atthe beginning of the circular list. In this ease. the extemal pointer Fad {inthe function iti ep) would point to the node next to the first node. This is represented in Fig. 11.22. : (28) hoad = tail->nexts (26) tail-onext = hoad~>noxty an (28) fron(hoad) Fig. 11.22 Deletion of the First Node of a Circular Linked List “The problem arises when the circular list contains omly one node. Then the statements (26), (27), and (28) will create a chaos. Therefore, the steps in Fig. 11.22 should be followed only if the list contains more than one node, If it contains a single node only (which can be ascertained by checking whether the next ficld of tail is pointing to itself}, then the pointer tail should set to NULL. indicating an empty circular list. Case 2: If the node to be deleted is the last node which is pointed to by tail (in the function it is +t). In this case after the deletion, the tail will be pointing to its predecessor which is shown in Fig. 11.23. vey eet. \ tmp (80) +t xt Fig. 11.23 Deletion of the Last Node in Circular Linked List To do this, the C statements will be as follows: prov-onext = trp->nex ar tail = prove G2 free (trp); ou ‘The definition of a function that will delete a node of a circular linked list is given 3 foltows: : void delnode(atruct node +e) t struct node ‘tmp, ‘prey, ‘heads int x, found-o7 ie (rest) Data Structures > 635 Peinte(*\n LINKED LIST 15 empry\n"); return; ' printt ("ENTER THE VALUE OF THE NODE WHICH IS TO BE DELETED :” sant ("9a") 6x); head=|*t)-onext, if (head->datas=x) ( tnp-head; Af (tmp->next !shead) (*t) ->next-head->nex: else *t-NULL: Eree(tmp) ; return: } prevehead trpshoad->noxts whi Le(tmp! head} { Lf (tmpoodatassx) Hl prov-onext=tmp->next: if (tmp==*t) stoprove free (cmp) found=1; break: 1 else ‘ prov-tnp? tmpetmp->next? 1 ) LE (£ound==0) print{(*\n NODE DOES NOT EXIST... ) 11.4.6 Sorting a Circular Linked List Sorting the nodes of a circular links consecutive nodes using the bubble list except the part of the code that counts ced list by exchanging the values of the data fields of the sort method is exactly the same as that of a singly linked the number of nodes. It is marked in bold face in the following code: void sort (struct node **8) ( struct node ‘tmp, *hoady 638. < Computer Programming and Data Structures int isisneletempr hoade(*t) >next: for (tmp=head->next ; tmp!=head; tmpstmp->next) Print£("\n Number of nodes=td\n"yn)7 for(i-0jicn-17ie+) ( tmp-hea for(j=033¢n-i ‘ if (tmp->data> [tmp->noxt) ->datal ( ne temp=tnp->data: tmp->data= (trp->next) ->dataz (emp=>next)->datastenp: : tmpstrp-onext: 11.5 Doubly Linked List Linked lists that have been discussed so far contain only one link (pointer) field which points to the next node in the list. Thus in both single and circular linked lists, one can traverse in ‘one direction only. It is observed that such lists sometimes seem to be too restrictive. For ‘example, note that in order to delete a node in single and circular linked lists, the predecessor of the node to be deleted has to be linked to its successor. However, because the list has only forward links, the predecessor of a node is not directly reachable from it, A doubly linked list overcomes this limitation. A doubly linked list is a type of an ordered list, in which cach node consists of two pointers. One is 10 store the address of the next node while the other stores the address of the previous node. Its also known as a two-way list ‘The specialty of this list is thatthe list can be traversed in both the directions, ic, both in forward as well as in backward directions. The concept of this type of linked list is used in ues. The hierarchical structure of the tree can be easily’ = represented using these double linked lists, The type PES mae declaration of a node of a doubly linked list containing @ imegers is as follows: ATS | 7 tie at Fig. 11.24 ANode in a Doubly Linked List a Pictorially. each node of a doubly linked list may be represented as shown in Fig. 11.24. Observe that the left link of the first node and right link of the Last mode are set to NULL: Note that like the other variants of linked lists, an empty doubly linked list is also denoted by null pointer. An extemal pointer head is kept to indieate the start of a doubly linked list Data Structures > 637 11.5.1 Operations on Doubly Linked List Insertion and deletion arc two basic operations on doubly linked lists. The steps to be followed are exactly same as singly linked list but only differ in the management of the two pointers. It has to be noted that the loop used 10 find the last node of a doubly linked list can be avoided if another external pointer tail is used to point to the last node of the list. In such cases. insertion and deletion at the end becomes easier. However, though inefficient, only head is considered here. As is clear by now any operation on linked list involves adjustments of links. Since the steps have been explained in detail for all the functions of singly linked lists as well as circular linked lists, it is not necessary ta give a step-by-step working of these for doubly linked lists. The working of doubly linked lists can be understood with the help of diagrams. Insertion of a Node in a Doubly Linked List This operation includes the following: © Appending a node # Inserting a node after a specified node Inserting a node before a specified node, which includes insertion at the beginning of the Figure 11.25 shows the schematic representation of insertion of a node in a doubly linked list. ion of node at the beginning co (6) Insertion of pode at any intermediate position Fig, 11.25. Insertion af a node at various positions in a doubly jinked list 638 < Computer Programming and Data Structures. Append a Node in a Doubly Linked List ‘The function definition to append a node in a doubly linked list is as follows: void append(steuct node **h) { struct node ‘p,tlasts psiecruct node *)malloc(si Af (peeNULL) { print£("\n Memory allocation unsuccessful. .")7 of(atruct node); return; , printf ("\n ENTER THE DATA..:*17 scanf ("#d", Gp=>data) : poonext-NULL? iE (the. p=>prevelast: ' Insertion of a Node After a Specified Node Insertion of a node after a specified node may be implemented with the following code: void insaft(struct node +h) t struct nede *p, ‘right: int ke Af (he=NULL) { print£("\n Linked List 19 EMPTY.,vold INSERTION”) ; return: Lis printf("\n Enter the node after which new node is to be inserted 1") scanf ("8d") 6h) : while(h!-NULL 6 he>datalsk) hehoonext s Ae theetWLL) i printé(*\n NODE DOES 'NOT ExIsT*); 1 Data Structures » 639 else t P =latruct pede *)mallocisi LE(p=-NULL) 7 t Printf("\n Menory allocation returns ’ Printf(™ \n Entor data: “); scant ("8d", gp-odata): cight-h->nexts pa>prov-h; poonexterights pof {struct noda)): unsuccessful. aD noxtep; if (right !-NULL] right->pr pi The statement marked is repeated here for the convenience of readers. AE (right !-NULL) right->pray Checking this is very important because if the desired nade is the Last node then its next field contains NULL, i.c.. the pointer right would contain NULL. Therefore, the statement right-2prev implies NULL~>prev which makes no sense. If the desired node after which new node has to be specified is given by position assuming that the first node is at position 1 and so on then the function insaft {) is as follows: yoid insatt (struct node ‘hp i int position, ts struct nodo ‘p,*right: if (h=-NULL) 1 printé(*\n Linked List is EMPTY..vold INSERTION"); print£("\n Enter the position after which \ new node is to be inserted scent (8d, sposition) 7 for(i=lsh!-NULL && ispoaitions++4) heh->nexts \ if (h=-NULL) printé™ list™, position) there are less than $d nodea in the \ else ‘ 840 ¢ Computer Programming and Data Structures ruct node} P s(struct node *)malloc(s: if (p==nULL) [ Printh(\n Memory allocation unsue: return: 1 printf(" \n Enter data seant (*¥d", sp—>datals right-h->noxty p->prev-h, poononteriqhty he>noxt ep: Ae(eightt NULL) right->prev=p; Insertion of a Node Before a Specified Node In case of doubly linked lists, from a particular node its predecessor can be found very easily with the aid of its prev ficld. There is no need to adopt any special trick to find the predecessor of a particular node. The definition of the following function would be suffi- cient enough to understand this operation. void insbef (struct node **h) 1 struct node *p, tmp, “left: int ki Af |[¢hs2NULL) i peintf("\n Linked List ia EMPTY..void INSERTION”); 1 printé("\n Enter the nede batore which scant ("td Gh) 7 /* INSERTION AT THE BEGINNING +/ LEC (+h) >data=k) [ new node is to be ingorted p a(stzuct node *)malloc(aizeof (struct node}); LE (p==MULL) t printf ("\n Memory allocation unsuccossfull.."); return: 1 print£(* \n Enter da scant ("8d") Gp->data) y p->preveNULLe poonent=ths Data Structures > 641 —>peeveps dataten) Pp s(struct node “mall Lt (peenutLy printt("\n 1 printfé(* \n Enter data secant ("t4", Gp=>dat left >provs pabprevslefer Insertion of a node before nth node follows the same logic as that for singly linked lists except that the predecessor can easily be reached by the use of the prev field of the node. Deletion of a Node from Doubly Linked List Deletion of a node from a doubly linked list may take place from any position in the list. Deletion of a node from a doubly linked fist from yanous positions is shown in Fig. 11.26. The deletion operation may be eamed out using the function deLnede (), Note that the function implements the deletion of a node at any position of the doubly linked list as depicted jg. 11.26; and it docs not use temporary pointers such as left or right to point to the predecessor or successor ofthe target node. The function de1node () iss follows: Ad detnata(st ruct node **h) jot node tps th? uLL) printf (*\n Linked List is EMPTY..vold CELETICH™) 2 returns 642 < Computer Programming and Data Structures head (2) Deletion of a node at the beginning "* - 7 (b) Deletion of a nodo at the end head WEL PEE (¢) Deletion of a node at an intermediate position Fig. 11.26 Deletion of a node at various positions in a doubly linked list, print€(*\n Entor tho data of the node to be Delete scant ("4d") ak) + J traverse the entire linked list +/ while (p! NULL] ( Lf (p->datan-k) ( Sf(pesth) /4if it is the first node +/ { the (th) >next: (Ch)-> prev = Nutt: ' else t /* Af the node is last nede +/ Af (p->next==NULL) (P->prev)~>next = MULL; else 7 if the node is intermediate */ ‘ (p>prev)~>next = p-next; (p->noxe)~>prey = 1 free(p); P->prav; Data Structures > 649 Sorting a Doubly Linked List To sort the nodes: of a doubly linked list, the same function can singly linked list. be used that has been used for Deleting all Nodes To dcletes all nodes of a doubly linked list, the same function used for singly linked lists can be used. 44.5.2. Advantages/Disadvantages of Doubly Linked Lists “The primary advantage of a doubly linked list is that navigation in cither direction is easily possible. This can be very useful. eg. if the Tist is used for storing strings, where the strings eines in a text file, One might store the “current line” of the text using a pointer to the appropriate node: if the user moves the cursor 10 the next or the previous line, a single pointer operation can restore the current line (0 its proper value. Similarly, if the user moves Pack ten lines, he/she can perform 10 pointer operations 10 B to the right line. For either of these operations. ifthe lists singly linked. one must sit the head of the list and traverse ‘until the proper point is reached. This can be very inefficient where large lists are concerned. "The primary disadvantages of doubly linked jists are that each node requires an extra pointer, requiring more space. and the ‘nsertion or deletion of a node takes a bit longer {because of more pointer operations) 11.6 Introduction to Cireular Doubly Linked List ‘A circular doubly linked list sa variant of a doubly linked list, in which the last node points pack to the first node. The entire list my ‘be accessed staring at any node and following links until one comes to the starting ‘node again, Here is the schematic representation ofa circular doubly linked list. In order to represent a doubly linked list, one can define a structure as follows: node ‘prey, *nexts 1 Fig. 11.27 Cireular Doubly Linked List ‘The two basic operations related to circular doubly linked lists are as follows: cular doubly tinked list Insertion of a node at the end as well the list follows a ‘combination of the logics that have been ed lists and circular linked lists. Figure 11.28 shows tion in the cireular doubly linked list. 1. Inserting @ node ina cit as at the beginning of followed in case of doubly lint pow to insert a node at an intermediate posi 644 < Computer Programming and Data Structures edlist { 82 prev next lo Fig. 11.28 Insert One Node to the Circular Doubly Linked List ‘The steps are as follows, These steps cannot be written in any other order. porpray = 4 Peonoxt © qe. é (qnext) prov = pa qronext =p 2, Delete a node from a circular doubly tinked list Figure 11.29 shows how to delete a node at an intermediate position of the circular doubly linked list. Fig, 11.29 Delete One Node from the Cireular Doubly Linked List ‘The steps for deletion are as follows: (paoprov) next = p->nex! i frootp): ont}=>prov = poprovs When the node to be deleted is the first node (pointed to by cdl st in the figure), the pointer edit will poin to the node next to the First node. The steps to be followed are as follews: edbiat-p->ne (p> pray) next {p=>naxt} ->prat~ freaip)s previ 11.7 Applications of Linked Lists mmm: Tn computer programming, linked lists are extensively used in Data Base Management Systems Process Management, Operating Systems, text editors, ete. An important application of the linked list is 10 represent polynomials and their manipulations, Representing polynomials using linked lists is advantageous because linked lists can accommodate a number of polynomials of growing'sizes so that their combined size does not ANTE RE NTS TET Data Structures > 645 exceed the total memory available. The general form of a polynomial of degree w is PU) Hag tax tay? tay +... Fan" Let us take P(x) = Gr* + 3x — 7 + 4x - 5, To represent each term of the polynomial using the nodes of a linked list, each node should consist of three elements, namely. coetficient, exponent, and a Tink to the next term. While maintaining the polynomial, it is assumed that the exponent of each successive term is less than that of the previous term. If this is not the case, one can also use a function jo build a list, which maintains this order. Once the linked list to represent the polynomial is ready then operations such as addition and multiplication can be performed. A term in the polynomial can be declared using the following structure definition. int expe Ivis clear from this declaration that a singly linked list has been used to represent aterm of the polynomial The functions to append the nodes for representing the polynomial and displaying it are similar to the fonctions append () and display). respectively. for singly linked lists. Hence, the readers should be able to develop these on their own, ‘The function addi tion () is used 10 carry out the addition of the two polynomials, Two polynomials are pointed (o by the pointers first and second which are passed (0 the function. In this function, the linked lists representing the 1wo polynomials are traversed ini! the end of any one list is reached, While traversing, the polynomials are compared on temm-by-term basis. If the exponents of the (wo terms being compared are equal, then their coefficients are acded and the result is stored in a third polynomial. If the exponents are not equal, ten the bigger exponent is added to the third polynomial. During the traversal if the ‘end of one list is reached, the control breaks out of the while loop. Now the remaining terms of that polynomial are simply appended to the resulting polynomial. Lastly, the result is displayed using a1 splay (). The function to add two polynomials is as follows: seocndy 848 4 Computer Programming and Data Structures ruct node *p, 7° if both fats are empty */ Ate ti NULL ) == MULL &2 second /* traverse till one node onda vhLiot these t= NEL Ae second t= LL 1 ‘ | te (sented <= my : t node) )? vented = (weruct node “Inalloclaizeot tetruct nde); pe centedy 1 ose ( poonext = (struct node *)mallec(sizeof (struct node)); P= ponent; 1 f* store a rm of larger degree if polynomial */ if( first—>exp < 1 p>coekf = accond-rcoekty . Po>exp ~ second-rexpe second = second->nexty /* move to the next node */ ) else if( first->exp > sacond=>exp) t prycowft = first->coatt: ond=2exp] first-7exp = first->exp: first = first->next; /+ move to the next node */ ' else if( first-rexp == second-2exp) ; . P>>cooff ~ first->coeff + second->cooft; firot->exp ~ first->exp; first = firet-snext 7+ move to the next node */ second = socond-onext; /+ mova ta tha next node */ , frassign remaining elawents of the first polynomial to the result */ while( first t= NULL) if( ‘third «= NULL) { “third = (struct node p> tthicd; ' @ *Imalloc(sizeof (struct node}): y Data Structures > 647 pronant = et node *Yralloctntzeof [struct node is © pooraees {alznot{oteuct models Prconl + tleatescoats prvoxp = firsroexp; first = fLrat-onoxt: ) Passiqn remainin * hing olenanta of the second polynceial to the result */ hilel seccnd I= MULL) 1 AE ‘third <= NULL) { sthird = (ateuct node *)malloc(aizeof (struct node))t p= ‘third: ) alse ( peonent = (struct noda *)malloc(sizeof (struct node) )i {= gecond-»coa: np ~ ssccnd=>oxp? second = aecond->noxts , poonont = MULE /* ot the ond of List append WULL/ 1 In some critical applications, it may be required to manipulate very large integers, which cannot be stored in variables of type int or Long in C. So a different representation scheme js required for large integers. Such a number can always e considered! 3s 2 special type of polynomial For instance, a number 1234 may be represented by the expression 1x 103 2 « 102 +3 x 10! #4 x 10” Clearly. the expression is of the order P(x) whe 20 + 3r+ 4 where x= 12, To generalize, any decimal integer of m digits can be expressed as the value of a(n ~ 1) degree polynomial. a P(x = Yaa! for x= 10 fv) where 05 4,59 "addition of two large integers specified in this manner is Very similar to addition of polynomials represented by linked lists. The only difference is that the coefficients must lie room 0 and 9. After addition. the coefficient may become more than 9, Let the sum of corresponding coefficients be S which is grecits than 9 and the corresponding exponent be Fre mat case, two nodes will rsull, One will contain ihe result of the expression S/10 as digit und E as the coefficient. The other node will contain the result of the expression S%10 as digit and f+ 1 as exponent, The Fesult of such addition is shown here, 648 < Computer Programming and Data Structures —GIis coott exp — 1s ~ Ts Tee eT}: P= polynomial representing fst integer, @ = polynomial representing second integer A= resultant polynomial alter addition Fig. 11.31 Addition of Coefficients (sigits) that Result in a Coefficient with Value More than 9 11.8 Disadvantages of Linked Lists In spite of the several advantages of using linked lists, there are obviously some shorteom- ings 100. One is pointer management. Pointers, if not dealt carefully, may lead to serious errors in execution. Linked lists also consume extra space than the space for actual data as the links among the nodes are maintained through the pointers. A major drawback of linked lists is that they are not suited for random access, To access a single node in linked storage, itis necessary to traverse a long path to reach the desired node, which takes a lot of time and space (because of using pointers). 11.9 Stacks and Queues == A stack is an ordered collection of elements into which new elements may be inserted and from which elements may be deleted at one end called the top of the stack, Given a stack $ = (a, dy, ....,). We Say that a, is the bottommost element, element a, is the topmost clement and element a; is set to be on the top of the clement A,_;,2SiEn, An example for a stack is a stack of plates arranged on a table. This means that the last item to be added is the first item to be removed, Hence a stack is also called as last-in-first- ‘out list or LIFO list, Also, the information can only be removed in the opposite orde which it was added to the stack. The most aecessible information in a stack is at the top of the stack and the least accessible information is at the bottom of the stack Apart from initialization, other allowed operations on stack are PUSH and POP. Insert ing an element into the stack is called PUSH and removing an clement from the stack is known as POP. Apatt from these operations, there is another operation known as PEEK which retums a copy of the object on top of the stack if the stack is not empty. Trying to pop an element off an empty stack is called underflow. While a stack is conceptually unbounded, successive Push (without Pop) will eventually cause the stack to overflow. Whether the stack is empty oF full must be verified before any element is popped or pushed. ‘A quere is an ordered homogencous group of items in which the items are added at one end {the rear) and are removed from the other end (the front). A.qucue can be though of like the tine of customers in the bank ot post office. When a customer atives in the queue, that person is added to back (tail) of the queue, When the clerk calls for the next customer to be served, thal person exits the queue atthe front ofthe queue. Since the first customer to join the queue isthe first one to be entertained, the queue is also known asa first-inefirst-out (FIFO) structure, Queues are very common in the everyday functions of computers, The most obvious is Printing queues. When you send multiple print. Jobs to a printer, each printing job is inserted N Data Structures > 649 au the rear of the queue in the order it was the printer. Any type of stream (hroughput executed by a CPU are usually in the form the order sent to Of VO will use a queue, Processes waiting to be of a queue, 11.9.1 Applications of Stacks Processing of subprogram calls One natural application of stacks which arises in com= putcr programming is the processing of subprogram calls and their terminations. The pro- gram must remember the place Where the call was made, so that it can return there after the subprogram is complete, __ Suppose we have three subprograms called A. B, and C and one main program; main invokes A, A invokes B. and B in tu invokes C. Then B will not have finished its work until C has finished and retumed. Similarly, main is the first to stant work, but it is the last to be finished; not until sometime after A has finished and returned. Thus, the sequence by which the subprogram actively proceeds is summed up as the property LIFO or FILO as shown below: Main begins = <— First in A begins Begins —— Lastin — First out — <— Last out From the above output, it cam be observed that the main program is invoked first but finished last, while subprogram C is invoked last but finished first. Hence to keep track of return addresses of the main program and subprograms, the only data structure required stack, Simuisting recursion Recursion is a technique that allows us ta break down a problem into one or more subprograms that are similar in form to the original problem. As recursive programs are most inefficient as far as their time and space complexities are concerned, there ig a need to convert them into iterative ones. To convert recursive programs into non- recursive ones, one has to use stacks. | , Evaluating arithmetical expression Calculators employing the postfix notation use a stick sttneire to hold values. The postfix notation allows one to specify arithmetic expres- ‘ses or setting precedence rules. For example, the calculation: oes wi sing parenthes s (ae 33 aaa pe writen down as follows in postfix notation: 4345 * 1 +, The expression is evaluated from the left 0 right using @ stac 1. When an operand is encountered, push, 2. When an pecation js encountered, pop two operands and evaluate, 3. Push the result. 650. ¢ Computer Programming and Data Structures [__ Operation Push ope 4 Push operand 43 Pop operands sind Add 7 Push operand 15 Pop operands and Multiply 35 Push operand 35,1 + Add 36 ‘At the end of the calculation, the final result, in this case 36, lies on the top of the stack, Stack Implementation of Recursion We have already studied recursive functions. We have seen that a recursive function calls itself to solve a smaller version of its task until a final call is made which does not require a call to itself, Recursive functions are implemented using system stack. | “The system stack stores the variables of the calling function on a system stack before the function makes a call to itself. This will be clear by looking at the following example, Write a program that prints the characters entered by the user in reverse order. Hincludecatdiom \_reverse_order(): print_in_reverse_order(); return 0; ' void print_in_reverse_order() 1 char che printf("\n Enter any character (enter . = scant |"tc", eh); if (ch f= "4 print_in_revorse_order(); else int ("te", ch); output Enter any character (enter . to atop) + B Enter any charactor (enter . to stop) + Y Enter any character (enter . to stop) : E. Enter any character (enter . to stop) + -EYB In the above program, we have made a call to print_in_reverse_order() four times, for characters ‘B', ‘Y', ‘E’, and ‘.', Think of recursive function as if you arc pulling 9 plate over another plate. So we have a scenario like the one given below. The first characlet entered is placed first. The second character is placed above the first character, so on and s0 forth. Then, these plates will be removed one by one. When the first plz removed. We get ths ehuracier “. The second plate gives’ the character ‘E’, and so on. This is shown I? ig. 11.32. Data Structures > 664 ‘Technically speaking, when the base case of the recursive function Bels execuled, the control is passed to the calling function. The calling ‘scheme of this function can be given as, | = |<] < B B Fig. 1152 Recursion using NOW sce how the function retums to main () system stack First, * is printed and control passes to E. Second, ‘E” is printed and control passes to Y Third. *Y” is printed and control passes 10 B. Fourth, *B" is printed and control passes to main (). 11.9.2 Array Implementation of Stack Array implementation A stack is usually implemented with a linked list, but can be implemented with an array. The array must have a finite size, say, MAX_SIZE. A variable fop returns the array index of the element at the top of the stack. That is, top denotes the Position of the array where a value was last inserted. It ranges from 0 to some large value 'N~ |. Stack is initialized with top = -1. The PUSH and POP operations can be described as shown in Fig. 11.33. Initially, the stack is empty and the top of the stack is pointing to the bottom of the st Stage [AJ: We added 14 and the top now points to it. Stage {B]: 23 is pushed and top is incremented by 1 Stage {C]: The stack is full, as the upper limit was set to 5. Stage [D]: The topmost element has been poped. The top gets decremented by | Stage [E]: 45, 4, 1, and 23 have been poped and top is now pointing to the bottom ‘most element. K. 1 TOP 23] 23} [23] wpe fv v4] ra PP “el “4 oO © Fig. 11.33 Push and Pop Operations on Stack 652 < Computer Programming and Data Structures Every time you push() an element by 1 and vice-versa, When the stack is empty, pointing to the empty stack. If you try to pus side the stack, the top of the stack gets incremented the bottom and top of the stack are same and h more clements than the upper limit of the stack, it will cause an overflow of data and vice-versa. C code segments for the above implementation are given below: Stack representation: fdefine SIZE 50 struct stack { int List {SIZE}: int tops he Stack creation and initialization: struct stack #2 8. 07 Push operation Function prototype declaration void puah(struct stack *, int) rion calling push (52,2) Function definition void push (struct stack *ap,int 2) t if (epe>top==SI2E) t printf ("\n OVERFLOH") + return; 1 spr>list [sp=>topes ]=x; return; 1 Pop operation Function prototype declaration int pop(ateuct stack *); Function calling nepoplés) 7 if(ate-1) printf ("\nPOPPED VALE 34d" nb; Function definition int pop(struct stack ‘sp i if (sp-rtop==0) t melee aay “KS EMPTY 1.0, UNDERFLON™); Data Structures Peek operation © Panction protonype dectanation © Bune nion calling ‘ © Function definition : print@(\n Undertlowsr ack « return (217 Write a program to perform Push, Pop and Peck operations on a stack array. #inchudec stdsosh> Hinctadecstrdngsh> Aietine 9 struct queue fatinde Pe(t\n VAINSERT 26RETRIEVE VEXTT Ane12 sant eats bet case Lapeint i ¢%\n ENTER THE NOME scant (MMT OIE e(eqeeds 654. Computer Programming and Data Structures peretclevicg)s id insert (struct queue ‘apyint * 11.9.3 Linked List Implementation of Stack Each data item is stored in a node of the linked list, which also holds a pointer to the next node on the list. The push and pop operations are implemented at the head of the list. The push and pop operations are illustrated in Fig. 11.34 ‘The node representation is given below: ‘Stack creation and initialization struct node *head: head=NULL Push and pop operations can be implemented as follows: Push operation * Function declaration void pust #include paNULL: “display (struc struc spopistruct st int peek(struct stack *)7 rain() ‘ int val, opticn: elrsce(}s do 1 Prince (*\n 4**°°MAIN MENUS = +99") 7 printf ("\n Ll. PUSHT)? printf (*\n 2. POP")1 printt("\n 3. PEEK"): printf("\n 4. DISPLAY"); printf(*\n 5. EXIT*); PEint£("\n *e4eeeree printf(*\n\n & scanf("#d", goption)? switch option] seeeesany er your option +); Peifim\n Biter the acanf:"¥a", aval)s — struct stack ‘display atruct stack “ptt prretopr Af (topeeNULL) printf (*\n STACK whi Le(pt et -NULL printe(t\ned”s prreptrsonext? 1s EMETIT'? 658 Computer Programming and Data Structures printf (™\n olse ‘ p-top pi o(ptr): return top: ’ ( return top->aatar ' 11.9.4 Array-based vs Linked-list-based Stacks ‘All operations for the array-based and linked stack implementations take constant time. The only basis for comparison is the total space (memory space) required. The array-based stack must declare a fixed size array initially, and some of that space is wasted whenever the stack is not full. The linked stack can shrink and grow, but requires the overhead of a link field (here the field is called as mext) for every node. 11.9.5 Queue Operations. The following operations are allowed on queues. Create/Initialize This operation creates a new empty queue. This operation must be done in order to make the queuc logically accessible. Enqueue This operation adds a new item to the rear of the queue. It is to be noted that the {queue must not be full. This statement holds good if the queue is implemented using an array and is mot applicable in linked list implementations with no declared maximum queue size. Dequeue This operation removes, and then returns the item at the front of the queue. ‘Again, the queue must not be empty. Like stack, a queue can be implemented using an array as well as a linked list. First we discuss the array implementation of the queue. The set of data elements is stored in an array ‘Two integer variables front and rear are to be taken which indicate the index of front and rear element, respectively. The front is initialized as 0 and rear as 1. Since the array size is finite, we also need to know Max_Size, ‘The queue is empty when Front > Rear. ‘The queue is also full when Front = Max Size — 1 struct queue Data Structures » 650 Enqueve and dequeue operations can be coded as follows: Enqueue operation Function declaration Wold ‘encanta wcewee Function calling we l6a, definition void enqueue (st *apeint x: rear == Max Dequeue operation int deque Function calling jequeue (6a) ¢ Function definition int dequeue (struct queue “ap ‘ St (apf > qp->r) un peinte(™ return| [igp->é return (qp->1. 11.9.6 Circular Queues In linear lists, we have studied so far that insertions can be done only at one end called rear and deletion is always done from the other end called the front. Look at the queue given below. apo] 7ztsit ee ee . 1 2 3 4 S$ 6 7 8 9 Here, front = 0 and rear = 9. sert another value, it will not be possible because the queue is empty space where the value can be inserted. Consider a sce- ‘are made. The queue will then be given as Now, if you want to ins completely full. There is no : nario in which two successive deletions T7Ls uf «] sal |] 2 1 2 . 5 6 7 3 8 9 660 Computer Programming and Data Structures Here, front = 2 and rear = 9- Now, if you want «a insert any new element—although there jg or) | ony space, insertion cannot be dane because the space 1 valle on the left side, In our algorithm, we have said if reaz = Max, then write OVERFLOW. So as per that, OVERFLOW condition ithe major drawback of a Tinear quewe. Even if space n be done once rear becomes MA-1, exists is available, no insertions Finally, it leads to wastage of space. "Te eter to this situation, we have two solutions, First, shift the ‘elements to the left so that the vacunt space can be occupied and inilized efficiently. But this can be very time consuming, espe. iy when the queue is quite large. ; ‘The second option is to use a circular queue. In circular queue, wu can think of a circular the first index comes right after the last index. Conceptually, yo queue as shown here. , The circular queue will be full, only when front=0 and rear-MAX~1. A circular ‘queue is implemented in the same manner as a linear queue is implemented. The only difference will be in the code that performs insertion and deletion operations. For insertion, ‘we will now have to cheek for three conditions which are as follows: « If front=0 and rear=HAx-2, then print “the circular queue is full” Look atthe queue given betow which illustrates this point o fot? sf [3% [as [als [2 t 2 3 4 s 6 7 8 rear=9 front=0 @ If rear! =max-1, then the value will be inserted and rear will be incremented. go [| 49 | 7 is | is | 36 [| as [ 21 front=0 1 2 3 458 6 7 rears5 9 © If front! #0 and rear=MAx-1, then the queue is not full. So, set rea: insert the new element there. 7 | 18 | 14 | 36 | 45 | 21 | 90 | 81 0 1 front=2 3 4 6s 6 7 8 rea Let us now have a look at the algorithm to inset an element in the circular queue. Step I: if FRONT = 0 and REAR = MAX-1, then Write "OVERFLOW" else if FRONT = =I and REAR = -1, then ‘Set FRONT = REAR = 0 ‘Set QUEUE[REAR] = VAL else iff REAR = MAX-1 and FRONT != 0 Set REAR = 0 Set QUEVE[ REAR] = VAL else Set REAR = REAR + I ea Data Structures > 064 Set QUEUE[REAR] = end if IREARI = VAL Step 2: Exit afer ene Row @ new element is added in a circular queue, let us now discuss how dele- a " ee formed in this case. To delete an element, we will check three conditions. ront=-1. then there are no elements in the queue. So an underflow condition will be reported front= rear=-1 oO 1 2 3 4 $ 6 7 8 9 * If the queue is not empty and after returning the value on front, if front=rear, then the queue has become empty and so, front and rear is set to -1 If the queue is not empty and after returning the value on front, if front=MAX-1. then front is set to 0. 72 63] 9 1s | 27 | 39 [| 81 0 1 2 3 4 rear=5 6 7 8 front=9 Let us now have a look at the algorithm to delete an clement from a circular queue. Step I: if FRONT = -1, then Printe “Overflow” SET VAL = -1 end if Step 2: Set VAL = QUEUE[FRONT] Step 3: if FRONT = REAR Set FRONT = REAR = -1 else if FRONT = MAX-1 Set FRONT = 0 else Set FRONT = FRONT + 1 end if end if 682 4 Computer Programming and Data Structures void ineert (void): int delete element (void): int peek(void); void dieplay(voidys main() { int option, val; elescr(): do 1 printf ("\n\n ***** MAIN MENU #7999") 2 peint£["\n 1. Insect an olement™); Peint£("\n 2. Delace an olement); Printf("\n 3, Pook")7 printf ("\n 4. Display the queue"! peinefi"\n 5. EXIT"); peintf(*\n sereeeres: Printf("\n\n Enter your option + ")7 scanf|"td", topt ion}; switeh (option) ( case 1: insert : breal case 2: val = dolete_elerent()s ahecnaslhy Print€("\n The nunber that was deleted is: $d", val); brea’ val = pook(): printé(*\n First value in the queue is: $d", val); break: case 4: display()+ broal : Jwhile(option!-5); gateh(): return 0; ’ void insert () 1 int num; printf ("\n Enter seanf ("4d") &nun); if(front=20 #6 raar==KAX-1) printé("\n OVERFLOW"): else if(fronte*-1 $6 rear i Eront=rar=0; queue [roar] snun; @ number to be inserted in the queue "se Data Structures > 663 peareedOEl! ke cerenctoo) senor “1 rear} fronterears Lf (front =eMAKe1) front=92, front +z , return valy rook) { quouel front] vold dieplay() let is peine£(n. if (front! YM 3 64 roar!=-2) te (frenterear) for (ietrontsleerenrsd++) peinet(\t $4% queue ll) ‘ tor (tetront sisMAxs 144) 664 « Computer Programming and Data Structures queue lt})# for(i iss se(*\t tdM, queuelil): 11.9.7 Array Representation of Queue Queues can be easily represented using linear arrays. As stated earlier, every queue will have front and rear variables that will point to the position from where deletions and insenions can be done respectively. Consider a queue given below. nls ]7 7 is 4 36 o i 2 3 4 5 (6 7 8 9 Here, front = 0 and rear = 5. If we want to add one more value in the list say, if we want to add another element with value 45, then rear would be incremented by 1 and the value would be stored at the position pointed by rear. The queue after addition would be, 219 7 18 14 36 | 45 ] o 1 2 3 a 36 7 8 9 Here, front = 0 and rear = 6. Every time a new element has to be added, we will repeat the same procedure. Now, if we want to delete an element from the queue, then the value of front will be incremented. Deletions are done from only this end of the queue. The queue after deletion will be, 9 [7 18 14 36 | 45 o 1 2 3 a 5 6 7 8 9 Here, front = 1 and rear = 6. However, before inserting an element in the queue we must check for overflow condi- tions. An overflow will occur when we will try to insert an element into 2 queue that is already full. When Rear = MAX ~ 1, where MAX is the size of the queue that is. MAX specifies the maximum number of elements in the queue. Note we have written MAX - |e because the index stars from 0. Similarly, before deleting an element from the queue, we must check for underflow condi- tion. An underflow condition occurs when we try to delete an element from a queue that is already empty. If front = 1 and rear = =1, this means there is no element in the queue. ‘Let us now have a look at the algorithms to insert and delete an ‘clement from a queue. Algorithm to insert an element in the queue Step 1: IF REAR=MAX-I, then; Write OVERFLOW (END OF IF] Step 2: IF FRONT SET FRO! ELSE SET REAR = REAR + 1 [END OF IF] Step 3: SET QUEUE[REAR] = NUM Step 4: Exit Algorithm to delete an element from the queue Step 1: IF FRONT 1 OR FRONT > REAR, then; Write UNDERFLOW ELSE SET FRONT = FRONT + 1 SET VAL = QUEUE[FRONT] {END OF IF] Step 2: Exit Write a program to implement a linear queue. Hinclude Hineluse feetine SIZz 100 struct stack ant List {SIZE}: int top: Me ine main 1 void push(steuct stack ‘intl int pop(s stack *}: int posk(atruet stack *) struct stack 37 int opt. nz a.topenli while) ‘ peintf(*\nl.PUSH 2,POP 3.PEEK ¢.EXIT\n")s print£("\n ENTER YOUR CHOICE #*)7 scant ("8d") 6opt) ¢ saith top) ( case lipeint£("\nENTER THE NO #")7 sean€ ("8d") 67 push (63/2) break: casa 2: n=popl6s)é ifinte-1) peinee(™\nPOPPED VALUE :d”yn)7 break: ease 3: nepook (ss)? Data Structures > 665 666 < Computer Programming and Data Structures senteay (*\RVALUE AT TOP :4d%n); case 4: oxit(oy: rerurn 0; , void push{struct stack ‘sprint x) 1 és Af(sp->top== S1ZE+1) 4 princ£("\n OVERF! 1 ap->liat (++ap->topl =x? In opteever ataek “ort i ittopotopeent) PeincE(*\nsTRCK 18 BIETY iyo WRORARLENN euch te 1 return (sp->List s->toE-}): Peck(struct stack sp) LE (ep->eo) t Printf("\nSTACK IS EMPTY i,e UKDERFLOW") : roturn (-1); , return(sp->1ist (sp->top]}; 1) 1 11.9.8 Linked List Representation of a Queue We have seen how a queue is created using an array. Although this technique of creating a queue is easy but the drawback is that the array must be declared to have some fixed size. If we allocate space for 50 elements in the queue and it uses hardly 20-25 locations then half of the space will be wasted. And in case we allocate only 10 or in other words few memory locations for a queue that might end up growing large and large then a lot of re-allocations will have to be done thereby creating a lot of overhead and consuming a lot of time. Incase, the queue is a very small one or its maximum size is known in advance. then array implementation of the stack gives an efficient implementation, But if the array size cannol be determined in advance, the other alternative, linked representation is used. The storage requirement of il i eile with n elements is O(n) and typical time ral ER the typical time requitement for opes OF ke :. nN Data Structures » 687 Ina linked queu ineddien of a es Sep series has two pats- one that stores data and the other that stores ‘we will also’ use’another pointe 1¢ START pointer of the linked list is used as FRONT. Here, reruns leer Caan called REAR which will store the audress of the last clement Geerend IF ERONT = GER All be done at the rear end and all the deletions are done at the = REAR = NULL, then it indicates that the queue is empty. Operations on a Queue A queue has wo basic operations: insert and delete, The Insert operation adds an element to the end of the queue of the stack and the Delete operation removes the element from the front or start of the queue. Apart from this, there is another operation Peek which returns the value of the first element of the queue. Consider the linked queue given below, = 9 fi 7 + 2 6 3]x FRONT REAR Insert Operation “The insert operation is used to insert an element in to the queue. The new element is added as the last element of the qucue. Consider the linked queue given below. U 7 374-44 6] +X) FRONT REAR To insert an element with value 9, we will first check if FRONT=NULL. If FRONT is equal to NULL. it means the queue is empty so..we will allocate memory for a new node, store the value in its data part and NULL in its next part. The new node will then be named as FRONT. However, if FRONT!= NULL. then we will insert the new node at the begin- ring of the linked stack and name this new node as TOP. Thus, the updated stack Becomes, 9 1 a 3 4[+21L4-16 BES FRONT REAR Algorithm to insert an element in to a linked queue Step 1: Allocate memory for the new node and! narne it as PTR Step 2: SET PTR->DATA = VAL Step 3: IF FRONT = NULL. then SET FRONT = REAR = PTR: SET FRONT->NEXT = REAR->NEXT = NULL ELSE SET REAR->NEXT = PTR SET REAR = PTR SET REAR->NEXT = NULL [END OF IF) Step 4: END 688 4 Computer Programming and Data Structures Delete Operation The delete opera is used 10 delete the element that was first inserted in the queue. That is, the delete operation deletes the element whose address is stored in FRONT. However, before deleting the value, we must first check if FRONT=NULL, because if this is the case then it means the queue is empty so no more deletions can further be done. If an attempt is made to. delete a value from a queue that is already empty, an UNDERFLOW message is printed. Consider the queue given below. 9 1 7 3 aT +-2 +414-BIx FRONT REAR To delete the clement, we will first check if FRONT=NULL. If the condition is false then we will delete the first node pointed by FRONT. The FRONT will now point to second clement of the linked queue. Thus, the updated queue becomes, i 3 4 {6 31x FRONT Algorithm to delete an element from a linked queue. Step 1: SET PTR = FRONT Step 2: IF FRONT = NULL, then Write “Underflow" ELSE FRONT = FRONT->NEXT FREE PTR [END OF IF| Step 3: END Write @ program to implement a linked queue. Hineludecatdio.h> Hincludececnio.h> atruet node fl int data; struct node *nexts le struct queue 1 struct node *front; struct node ‘rear: mn etruct queue ‘qi vold creata_queua(struct queue * ptruct queue tinsert (struct queue *, int); ateuct queus ‘dele! atruct queus ‘display{struct queue +); int peek(struct queue +); element (struct queue +); REAR Data Structures > 669 rain() fi elescr(): do 4 Peinte("\n **+esMAIN MENUS# +6") 5 Printé("\n 1. INSERT"); printf(*\n 2. DELETE"); printf("\n 3, PEEK: printf{("\n 4, DISPLAY" printf("\n 5, EAIT"); pri printf ("\n\n Enter your option + “)s peané ("$d") soption); switch (option) ‘ (\n ttteeeeeenes case 1: printf(*\n ENter the number to be inserted in the queue : “): scang("#a", Eval); q = insert(asval)s break: case 2: qe delece_elenent (gli break case 35 val = peekifront); printf ("\n The value stored at the top of the stack 19 + td", val); break? case q = display(a: breaks ) Hwhi le (option !=51 geteh (i return 1 void create queve(atruct queue ‘a) 1 struct queye ‘insert(struct queue ‘int val) t struct node ‘ptry pir = (struct node‘}nalloc(eizeof {struct node *))7 per-rdatacvaly Lf (qe>front=front->: “HULL? toq-> rear->nax ' else 4 ao>eear-onext = ptry q>rearept, q7>rear->next-NULL: 1 retuen ai ! . struct queue ‘display(struct queue *q) ( struct node “ptr ptreqensien if (pent) PEintE(*\n QUEUE IS EMPTY"): else t peiaté(\n"); while (pert! =q->enary 1 printf("aa\e*, ptr->data); poreptr-onex! 1 printf(med\e", per->data); ’ return q ’ struct queue ‘delet ( struct node ‘pee; presq->front; Le (q->tzont=aNTILL) print£("\n UNDERFLON") ; else ‘ slement (struct queue *q) a->Eront =qn>front~>next: printf("\n The value being doloted is : freo(perd: 1 return qz 1 int peok(struct queue +q) ( roturn q->front=>data; , ptr->data) + Data Structures » 671 11.9.9 Array-based vs Linked-list-based Queues. The arrays that we used to implement the queues were declared to have the size SIZE. This size remains fixed once the program is writien and it cannot be changed while the program is running. Thus while writing a program, we had to decide the maximum amount of memory that would be needed for our arrays and we set this much memory aside in the declarations. If the number of elements stored in the queve is small, then much of this space would never be used. However, if we decide to store a large number of items in the queue, then we ‘may exhaust the space set aside and encounter overflow, even when the computer memory is ‘not fully used, simply because our original bounds on the array were too small. Thus, arrays suffer from the necessity 1o declare the size of the array before running the program. If we are to overcome this limitation, we need to use linked list. ‘A linked list implementation of a queue is done by linking together elements to form a chain. In a linked list implementation of a queue, the link field of the node will either point to the next node in the queue or to the head of the queue. ‘Two pointers are needed to mark the front and back of the queue, these are front and rear, Without these pointers, it would be very casy to lose track of where the queue begins and ends. Fig. 11.35 illustrates the queuing operation. onqueve (5) tromQ— ST IQ rear (Step 2) enqueve (10) dequeue () tear front “Ts +—-fro] front Tro] (Step 3) (Step 4) Fig. 11.35 Queuing Operation Using Linked List To represent 2 queve using linked list, the self-referential structure would be as follows + node The queve is initialized as below: front = rear = MULL i “The enqueue operation can be implemented as follows: ‘* Function declaration void adayistruct ede © Function calling 872 4 Computer Programming and Data Structures © Function definition “ void addq (struct node +*f, atguct node ttr, int item) 1 struct node *q 7 J+ craato now node */ q = (struct node *) malloc (sizeof (struct nede)) ; Af(q e= NULL) ( peintf{*queue is full"); roturn; ' q -> data = item ; q > Link = NULL 7 /* if the quous ts ompty */ if (tf e= NULL) ‘fat else [try => link = ai treat H ‘The dequeue operation can be implemented as follows: * Function declaration int delq (struct node **, struct node *4) ‘© Function calling item = delq [éfront, rear) ; ig(item!= -1) printt ("sd", item) : © Function definition /* removes an element from front of queue */ int delq (struct node **f, struct nede **r} { struct nede *q + int item : 7* Af queue is empty */ if (+f == NULL) ' Printé (“queue is empty") return(-1)3 1 else 1 7* dolate the node */ asf: item = q -> data ; th = q-> link; froo (a 7* SE on deletion the quouo has become onpty */ if (°f — NULL) or MULL? roturn (item) + ) P| Data Structures > 673 Pm p breaks (top, val) top = popttop)? brake case 31 val = peakitopls Cyr The Yalue stored a stack ie t 8d%, vallr top = display(tep): breaks ) Loloption!=5) 7 getchiye Foturn Oy ck *push(struct stack ‘top, teuct stack “ptr: PIE + (struct stack*)malloc(ai: Fir-pdataqvaly S€(top==KULL) ‘ top=pte: top->next «MULL; 3 else 1 pte-pnoxt=top; top=ptey 1 return top: uct stack ‘dieplayleteuct stack * teuct stack *ptry pir-tops LE (top==NULL) peint€("\n STACK IS EMPTY")y else ‘ while (ptrt=NuLLy 1 printe(*\ntd™, ptr->data): pte=ptr=>next, ’ 1 return tops , atruct atack *pop(struct stack *top) ‘ struct stack *ptrs 674 4 Computer Programming and Data Structures epetepeoneney being deleted 4 printe(*\n The from iptrls return topr int peok(struct atack *top) return top=>dat ) Write a program to implement a linked queue. fincludecstdio.h> #include struct node t int data; struct node *next: M struct queue t struct node ‘front; struct node ‘rear: h struct queue *q: void create_queue(struct queue *): struct queue ‘insert (struct queue *, int): struct queue ‘delete element (struct queue *): struct queue ‘display(struct queue *): int peek(struct queue *); main() ( int val, option; create_queue(q) ; clrser(); do fl print ("\n *****MAIN MENUS #**~); printf (*\n 1. INSERT”); printt("\n 2. DELETE”): printt("\n 3. PEEK”); printf(*\n 4. DISPLAY"); printf("\n 5. EXIT™): printe(™\n aeeeeeny, Data Structures » 675 Peintf(™\n\n Enter your scant (“ta", Soption); switch (option) ( option : “); case 1: Printf("\n ENter the number to be inserted in the queue : “); Scanf("td", eval); @ = insert (q,val); break: case 2: a= delete element (q); break: case 3: val = peek(front): Print£("\n The value stored at the top of the stack is + #4”, val); break: case 4: @ = display(q); break: } Jwhile {option getch(); return 0; ) void create_queue(struct queue *q) £ qr>rear=NULL; q->front=NULL: ' struct queue *insert(struct queue *q,int val) ' struct node ‘ptr: ptr = (struct node*)malloc(sizeof (struct node *}): ptr->data=val L£(q->front=-NULL) i : q->front = ptr: q->rear = ptrs qr>front->next=q->rear-pnext=NULL; Sys } else { q->rear->next = ptré qr>reareptr: q->rear->next=NULL: ) return a? ) struct queue *display(struct queue *q) t 878 < Computer Programming and Data Structures lf struct node *ptr? ptr=q->front; Af (per==NULL) . Print£("\n QUEUE IS EMPTY")? else ( print£(*\n"); while (ptr!=q->rear) { printf("ed\t”, ptr->data) ; ptr=ptr->next; h printf (“td\t", ptr->data): ) return qz ) struct queue *delete_element (struct queue *q) { struct node *ptr; ptr=q->front; if (q->front==NULL) print£("\n UNDERFLOW"); else i q->front=q->front->next: printf£(*\n The value being deleted is : #d”, ptr->data); free (ptr); ) return q: ) int peek(struct queue *q) ( return q->front->data; ) 11.10 Infix, Postfix and Prefix Notation mma Infix, Postfix, and Prefix notations are three di algebraic expressions, But before learning about first see what an infix notation is. algebraic expressions. While writin erator is placed in between the 0} rere fferent but equivalent notations of writing Prefix notation and postfix notation, let us We all are familiar with the infix notation of writing ig an arithmetic expression using infix notation, the OP perands. For example, A+B. here, plus operator is placed between the two operands A and B, Although for us it is easy to write expressions using infix Rotation but computers find it difficult to parse. Computers work more efficiently with expressions written using prefix and postfix notations, Given an expression in infix notation is difficult to parse because the computer needs alt of information to evaluate the expression, Information is needed about operator precedent. associativity rules and brackets which overrides these rules, Data Structures > 677 teiunioomee im sive by Jan £ukasiewicz who was a Polish logician, mathematician, Polish noutvon at at as t@ develop a parenthesis-free prefix notation (also krown 38 et 4 postfix notation which is better known as Reverse Polish Notation or In posifix notation, as the name suggests, the operator is placed after the operands. For example, if an expression is written as A+B in infix notation, the same expression can be written AB+ in postfix notation. The order of evaluation of a postfix expression is always from left to right. Even brackets can not alter the order of evaluation Similarly, the expression (A + B) * C is written as [AB+}*C AB4C* in the postfix notation, A postfix operation does not even follow the rules of operator precedence. The operator which occurs first in the expression is operated first on the operands. For example. given a postfix notation AB+C*, While evaluation, addition will be performed prior to multiplication, Exercise: Convert the following infix expressions into postfix expressions (A-B) * (C+D) [AB-| * [(CD+] ‘AB-CD+* (A+B)/(C+D)-(D*E) TAB+] / [CD+] - [DE*] [AB+CD+/} - [DE*] AB+CD+/DE*- ‘Thus we sec that in a postfix notation, operators are applied to the operands that are immediately left to them. In the example, AB+C*, + is applied on A and B, then * is applied ‘on the result of addition and C. Although a Prefix notation is also evaluated from left to right but the only difference between a postfix notation and a prefix notation is that in a prefix notation, the operator is placed before the operands. For example, if A+B is an expression in infix notation, then the corresponding expression in prefix notation is given by +AB. While evaluating a prefix expression, the operators are applied to the operands that are present immediately on the right of the operator. Like postfix, prefix expressions also do not follow the rules of operator precedence, associativity and even brackets cannot alter the order of evaluation. Exercise: Convert the following infix expressions into prefix expressions, (A+B)*C (4AB)*C *+ABC (A-B) * (C+D) [-AB] * [+CD] *-AB+CD (A+B)/(C + D)-(D*E) [+AB] / [+CDI - [*DE} [ / +AB+CD] - [*DE) ~/+AB+CD*DE

Das könnte Ihnen auch gefallen