Like this document? Why not share!

670

-1

-1

Published on

No Downloads

Total Views

670

On Slideshare

0

From Embeds

0

Number of Embeds

0

Shares

0

Downloads

0

Comments

0

Likes

1

No embeds

No notes for slide

- 1. ecomputernotes.com Data Structures Lecture No. 06___________________________________________________________________Data StructuresLecture No. 06Stack From the Previous LectureWe started discussing Stack data structure and its implementation in the previouslecture. We also implemented stack structure using an array and wrote code for itspush(), pop() and top() operations. We realized that we have to specify the size of thearray before using it whether we declare it statically or dynamically. Arrays are offixed size and when they become full, no more elements can be added to them. Inorder to get to know that the array has gone full, we wrote the isFull() method. Itbecame the responsibility of the user of the stack structure to call isFull() methodbefore trying to insert an element using the push() method otherwise the wholeprogram could crash.isEmpty() method is implemented as a stack can be empty like a list or set structures.It is important to understand that isFull() method is there in stack implementationbecause of limitation of array but isEmpty() method is part of the stack characteristicsor functionality.As previously in the implementation of list structure, we used linked list whileallocating nodes dynamicallyin order to avoid the fixed sized limitation of array. Nowin this case also, again to overcome the limitation of array, we are going to make useof linked list in place of array to implement the stack data structure. Let s see, how wecan implement a stack structure using linked list and how the implementation codewill look like internally.Stack Using Linked ListWe can avoid the size limitation of a stack implemented with an array, with the helpof a linked list to hold the stack elements.As needed in case of array, we have to decide where to insert elements in the list andwhere to delete them so that push and pop will run at the fastest.Primarily, there are two operations of a stack; push() and pop(). A stack carries lifobehavior i.e. last in, first out.You know that while implementing stack with an array and to achieve lifo behavior,we used push and pop elements at the end of the array. Instead of pushing andpopping elements at the beginning of the array that contains overhead of shiftingelements towards right to push an element at the start and shifting elements towards Page 1 of 3
- 2. ecomputernotes.com Data Structures Lecture No. 06___________________________________________________________________left to pop an element from the start. To avoid this overhead of shifting left and right,we decided to push and pop elements at the end of the array.Now, if we use linked list to implement the stack, where will we push the elementinside the list and from where will we pop the element? There are few facts toconsider, before we make any decision:- For a singly-linked list, insert at start or end takes constant time using the head and current pointers respectively. As far as insertion is concerned, it is workable and equally efficient at the start and end.- Removing an element at the start is constant time but removal at the end requires traversing the list to the node one before the last. So removing from the start is better approach rather than from the end.Therefore, it makes sense to place stack elements at the start of the list becauseinsertion and removal take constant time. As we don t need to move back and forthwithin the list, therefore, there is no requirement of doubly or circular linked list.Singly linked list can serve the purpose. Hence, the decision is to insert the element atthe start in the implementation of push operation and remove the element from thestart in the pop implementation. headtop 1 7 1 7 5 2 5 2 Fig 1. Stack using array (on left side) and linked list (on right side)There are two parts of above figure.On the left hand, there is the stack implementedusing an array. The elements present inside this stack are 1, 7, 5 and 2. The mostrecent element of the stack is 1. It may be removed if the pop() is called at this pointof time. On the right side, there is the stack implemented using a linked list. Thisstack has four nodes inside it which are liked in such a fashion that the very first nodepointed by the head pointer contains the value 1. This first node with value 1 ispointing to the node with value 7. The node with value 7 is pointing to the node withvalue 5 while the node with value 5 is pointing to the last node with value 2. To makea stack data strcuture using a linked list, we have inserted new nodes at the start of thelinked list.Let s see the code below to implement pop() method of the stack. int pop() { 1. int x = head->get(); Page 2 of 3
- 3. ecomputernotes.com Data Structures Lecture No. 06___________________________________________________________________ 2. Node * p = head; 3. head = head->getNext(); 4. delete p; 5. return x; }At line 1, we have declared x as an int and retrieved one element from the node of thestack that is pointed by the head pointer. Remember, the Node class and its get()method that returns the value inside the node.At line 2, p is declared as a pointer of type Node and address inside the head pointer isbeing saved inside this p pointer.At line 3, the address of the next node is being retrieved with the help of the getNext()method of the Node class and being assigned to head pointer. After this assignment,the head pointer has moved forward and started pointing to the next element in thestack.At line 4, the node object pointed by the pointer p is being deallocated (deleted).At line 5, the function is returning the value of the node retrieved in step 1. headtop 7 1 7 5 2 5 2 Fig 2. A node removed from the stack after the pop() callLet s see the code of the push() method of the stack: void push(int x) { 1. Node * newNode = new Node(); 2. newNode->set(x); 3. newNode->setNext(head); 4. head = newNode; }In line 1, a new node is created, using the new Node() statement and returned pointeris assigned to a pointer newNode. So newNode starts pointing to the newly createdNode object.In line 2, the value 2 is set into the newly created Node object.In line 3, the next node of the newly created node is set to the node pointed to by thehead pointer using setNext(head). Page 3 of 3
- 4. ecomputernotes.com Data Structures Lecture No. 06___________________________________________________________________In line 4, the head pointer is made to point to the newly created node. head top 9 7 7 5 2 5 2 newNode 9 Fig 3. A node added to the stack after the push(9) callThese are two primary methods of a stack. By using the push() method, we can keepon pushing elements and using the pop() methods. Elements can be removed from thestack till the time, it gets empty. As discussed earlier, isEmpty() is the stackcharacteristic but isFull() was implemented because of the size limitation of the array.We are no more using array to implement a stack. Rather, we have used linked listhere for stack implementation. Therefore, isFull() might not be required here. Aninteresting question arises here. Can we add infinite elements to the stack now. Weshould remember that this program of stack will run on computer that definitely has alimited memory. Memory or Address space of a computer is the space (physicalmemory and disk space) that can be addressed by the computer which is limitedinlcuding the limited physical memory. Disk space is used as the virtual memory ( wewill not discuss virtual memory in detail here). A computer with 32-bit addressing canaddress upto 232-1 memory locations and similarly a computer with 64-bit addressingcan address upto 264-1 addresses. If this address space becomes full, the stack willdefinitely be full. However, the stack implementation is not liable for this fullness ofaddress space and it is the limitation of a computer address space. Therefore, we don tneed to call isFull() before pushing the element. Rather, isEmpty() is called beforepoping an element from the stack.Let s see the remaining methods of the stack while using linked list to implement it. int top() { return head->get(); } int isEmpty() { return ( head == NULL ); }The above-mentioned methods i.e. top() and isEmpty() are very simple functions. Onestatement inside the top() is retrieving the top element (pointed to by the head pointer)from the stack and returning it back by value. It is important to note that top() is notremoving the element from the stack, but only retrieving it. The one statement inside Page 4 of 3
- 5. ecomputernotes.com Data Structures Lecture No. 06___________________________________________________________________isEmpty() is a check to see if the head pointer is not pointing to any node and it isNULL. If the head pointer is NULL that means the stack is empty, the method returnstrue otherwise it returns false.All four operations push(), pop(), top() and isEmpty() take constant time. These arevery simple methods and don t contain loops. They are also not CPU hungryoperation. Also note that we have not written isFull() while implementing stack withthe linked list.Stack Implementation: Array or Linked ListSince both implementations support stack operations in constant time, we will seewhat are the possible reasons to prefer one implementation to the other.- Allocating and de-allocating memory for list nodes does take more time than pre- allocated array. Memory allocation and de-allocation has cost in terms of time, especially, when your system is huge and handling a volume of requests. While comparing the stack implementation, using an array versus a linked list, it becomes important to consider this point carefully.- List uses as much memory as required by the nodes. In contrast, array requires allocation ahead of time. In the previous bullet, the point was the time required for allocation and de-allocation of nodes at runtime as compared to one time allocation of an array. In this bullet, we are of the view that with this runtime allocation and de-allocation of nodes, we are also getting an advantage that list consumes only as much memory as required by the nodes of list. Instead of allocating a whole chunk of memory at one time as in case of array, we only allocate memory that is actually required so that the memory is available for other programs. For example, in case of implementing stack using array, you allocated array for 1000 elements but the stack, on average, are using 50 locations. So, on the average, 950 locations remain vacant. Therefore, in order to resolve this problem, linked list is handy.- List pointers (head, next) require extra memory. Consider the manipulation of array elements. We can set and get the individual elements with the use of the array index; we don t need to have additional elements or pointers to access them. But in case of linked list, within each node of the list, we have one pointer element called next, pointing to the next node of the list. Therefore, for 1000 nodes stack implemented using list, there will be 1000 extra pointer variables. Remember that stack is implemented using singly-linked list. Otherwise, for doubly linked list, this overhead is also doubled as two pointer variables are stored within each node in that case.- Array has an upper limit whereas list is limited by dynamic memory allocation. In other words, the linked list is only limited by the address space of the machine. We have already discussed this point at reasonable length in this lecture.Use of StackExamples of uses of stack include- traversing and evaluating prefix, infix and postfixexpressions.Consider the expression A+B: we think of applying the operator + to the operandsA and B. W e have been writing this kind of expressions right from our primaryclasses. There are few important things to consider here: Page 5 of 3
- 6. ecomputernotes.com Data Structures Lecture No. 06___________________________________________________________________Firstly, + operator requires two operators or in other words + is a binary operator.Secondly, in the expression A+B, the one operand A is on left of the operator whilethe other operand B is on the right side. This kind of expressions where the operator ispresent between two operands called infix expressions. We take the meanings of thisexpression as to add both operands A and B.There are two other ways of writing expressions:− We could write +AB, the operator is written before the operands A and B. These kinds of expressions are called Prefix Expressions.− We can also write it as AB+, the operator is written after the operands A and B. This expression is called Postfix expression.The prefixes pre and post refer to the position of the operator with respect to the twooperands.Consider another expression in infix form: A + B * C. It consists of three operands A,B, C and two operator +,* . We know that multiplication () is done before addition(+), therefore, this expression is actually interpreted as: A + (B * C). Theinterpretation is because of the precedence of multiplication (*) over addition (+). Theprecedence can be changed in an expression by using the parenthesis. We will discussit a bit later.Let s see, how can we convert the infix expression A + (B * C) into the postfix form.Firstly, we will convert the multiplication to postfix form as: A + (B C *). Secondly,we will convert addition to postfix as: A (B C *) + and finally it will lead to theresultant postfix expression i.e. : A B C * +. Let s convert the expression (A + B) * Cto postfix. You might have noticed that to overcome the precedence of multiplicationoperator (*) we have used parenthesis around A + B because we want to performaddition operation first before multiplication. (A + B) * C infix form (A B +) * C convert addition (A B +) C * convert multiplication AB+C* postfix formThese expressions may seem to be difficult to understand and evaluate at first. Butthis is one way of writing and evaluating expressions. As we are normally used toinfix form, this postfix form might be little confusing. If a programmer knows thealgorithm, there is nothing complicated and even one can evaluate the expressionmanually.Precedence of OperatorsThere are five binary operators, called addition, subtraction, multiplication, divisionand exponentiation. We are aware of some other binary operators. For example, allrelational operators are binary ones. There are some unary operators as well. Theserequire only one operand e.g. and +. There are rules or order of execution ofoperators in Mathematics called precedence. Firstly, the exponentiation operation isexecuted, followed by multiplication/division and at the end addition/subtraction isdone. The order of precedence is (highest to lowest): Page 6 of 3
- 7. ecomputernotes.com Data Structures Lecture No. 06___________________________________________________________________ Exponentiation ↑ Multiplication/division *, / Addition/subtraction +, -For operators of same precedence, the left-to-right rule applies: A+B+C means (A+B)+C.For exponentiation, the right-to-left rule applies: A ↑ B ↑ C means A ↑ (B ↑ C)We want to understand these precedence of operators and infix and postfix forms ofexpressions. A programmer can solve a problem where the program will be aware ofthe precedence rules and convert the expression from infix to postfix based on theprecedence rules.Examples of Infix to PostfixLet s consider few examples to elaborate the infix and postfix forms of expressionsbased on their precedence order: Infix Postfix A+B AB+ 12 + 60 23 12 60 + 23 (A + B)*(C D ) AB+CD * A ↑ B * C D + E/F A B ↑ C*D E F/+In the next lecture we will see, how to convert infix to postfix and how to evaluatepostfix form besides the ways to use stack for these operations. Page 7 of 3

No public clipboards found for this slide

×
### Save the most important slides with Clipping

Clipping is a handy way to collect and organize the most important slides from a presentation. You can keep your great finds in clipboards organized around topics.

Be the first to comment