Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
06 Stacks, Queues, and Deques Hongfei Yan Mar. 30, 2016 Contents • • • • • • • • • • • • • • • 01 Python Primer (P2-51) 02 Object-Oriented Programming (P57-103) 03 Algorithm Analysis (P111-141) 04 Recursion (P150-180) 05 Array-Based Sequences (P184-224) 06 Stacks, Queues, and Deques (P229-250) 07 Linked Lists (P256-294) 08 Trees (P300-352) 09 Priority Queues (P363-395) 10 Maps, Hash Tables, and Skip Lists (P402-452) 11 Search Trees (P460-528) 12 Sorting and Selection (P537-574) 13 Text Processing (P582-613) 14 Graph Algorithms (P620-686) 15 Memory Management and B-Trees (P698-717) Contents 6.1 Stacks 6.2 Queues 6.3 Double-Ended Queues 6.1 Stacks 6.1.1 The Stack Abstract Data Type 6.1.2 Simple Array-Based Stack Implementation 6.1.3 Reversing Data Using a Stack 6.1.4 Matching Parentheses and HTML Tags A stack is a collection of objects that are inserted and removed according to the last-in, first-out (LIFO) principle. • A user may insert objects into a stack at any time, but may only access or remove the most recently inserted object that remains (at the so-called “top” of the stack). • The name “stack” is derived from the metaphor of a stack of plates in a spring-loaded, cafeteria plate dispenser. In this case, the fundamental operations involve the “pushing” and “popping” of plates on the stack. E.g., a PEZ candy dispenser, which stores mint candies in a spring-loaded container that “pops” out the topmost candy in the stack when the top of the dispenser is lifted Figure 6.1: A schematic drawing of a PEZ dispenser; a physical implementation of the stack ADT. (PEZ is a registered trademark of PEZ Candy, Inc.) ? ? Applications of Stacks • Direct applications • Page-visited history in a Web browser • Undo sequence in a text editor • Chain of method calls in a language that supports recursion • Indirect applications • Auxiliary data structure for algorithms • Component of other data structures Abstract Data Types (ADTs) • An abstract data type (ADT) • Example: ADT modeling a simple is an abstraction of a data stock trading system structure • The data stored are buy/sell orders • The operations supported are • An ADT specifies: • Data stored • Operations on the data • Error conditions associated with operations • order buy(stock, shares, price) • order sell(stock, shares, price) • void cancel(order) • Error conditions: • Buy/sell a nonexistent stock • Cancel a nonexistent order 6.1.1 The Stack Abstract Data Type • The Stack ADT stores arbitrary objects • Insertions and deletions follow the lastin first-out scheme • Think of a spring-loaded plate dispenser • Main stack operations: • push(object): inserts an element • object pop(): removes and returns the last inserted element • Auxiliary stack operations: • object top(): returns the last inserted element without removing it • integer len(): returns the number of elements stored • boolean is_empty(): indicates whether no elements are stored By convention, we assume that a newly created stack is empty, and that there is no a priori bound on the capacity of the stack. Elements added to the stack can have arbitrary type. Example 6.3: The following table shows a series of stack operations and their effects on an initially empty stack S of integers. 6.1.2 Simple Array-based Stack Implementation • A simple way of implementing the Stack ADT uses an array • We add elements from left to right • A variable keeps track of the index of the top element … S 0 1 2 t Array-based Stack (cont.) • The array storing the stack elements may become full • A push operation will then need to grow the array and copy all the elements over. … S 0 1 2 t The Adapter Pattern • The adapter design pattern applies to any context where we effectively want to modify an existing class so that its methods match those of a related, but different, class or interface. Implementing a Stack Using a Python List • use the adapter design pattern to define an ArrayStack class that uses an underlying Python list for storage. • One question that remains is what our code should do if a user calls pop or top when the stack is empty. • Our ADT suggests that an error occurs, but we must decide what type of error. • When pop is called on an empty Python list, it formally raises an IndexError, as lists are index-based sequences. • That choice does not seem appropriate for a stack, since there is no assumption of indices. • Instead, we can define a new exception class that is more appropriate. Code Fragment 6.1 defines such an Empty class as a trivial subclass of the Python Exception class. Array-based Stack in Python We choose the name ArrayStack to emphasize that the underlying storage is inherently array based.) Example © 2013 Goodrich, Tamassia, Goldwasser Stacks 21 Performance and Limitations • Let n be the number of elements in the stack • The space used is O(n) • Each operation runs in time O(1) (amortized in the case of a push) Avoiding Amortization by Reserving Capacity • In some contexts, there may be additional knowledge that suggests a maximum size that a stack will reach. • In the analysis of lists from Section 5.4.1, we emphasized that it is more efficient in practice to construct a list with initial length n than it is to start with an empty list and append n items (even though both approaches run in O(n) time). 6.1.3 Reversing Data Using a Stack 6.1.4 Parentheses Matching and HTML Tags • In our first application, we consider arithmetic expressions that may contain various pairs of grouping symbols, such as • Parentheses: “(” and “)” • Braces: “{” and “}” • Brackets: “[” and “]” • Each “(”, “{”, or “[” must be paired with a matching “)”, “}”, or “[” • • • • • correct: ( )(( )){([( )])} correct: ((( )(( )){([( )])} incorrect: )(( )){([( )])} incorrect: ({[ ])} incorrect: ( Parentheses Matching Algorithm Algorithm ParenMatch(X,n): Input: An array X of n tokens, each of which is either a grouping symbol, a variable, an arithmetic operator, or a number Output: true if and only if all the grouping symbols in X match Let S be an empty stack for i=0 to n-1 do if X[i] is an opening grouping symbol then S.push(X[i]) else if X[i] is a closing grouping symbol then if S.is_empty() then return false {nothing to match with} if S.pop() does not match the type of X[i] then return false {wrong type} if S.isEmpty() then return true {every symbol matched} else return false {some symbols were never matched} Parentheses Matching in Python Performance • If the length of the original expression is n, the algorithm will make at most n calls to push and n calls to pop. Those calls run in a total of O(n) time, • even considering the amortized nature of the O(1) time bound for those methods. • Given that our selection of possible delimiters, ({[, has constant size, auxiliary tests such as c in lefty and righty.index(c) each run in O(1) time. • Combining these operations, the matching algorithm on a sequence of length n runs in O(n) time. Matching Tags in a Markup Language For fully-correct HTML, each <name> should pair with a matching </name> <body> <center> The Little Boat <h1> The Little Boat </h1> </center> <p> The storm tossed the little boat like a cheap sneaker in an old washing machine. The three drunken fishermen were used to such treatment, of course, but not the tree salesman, who even as a stowaway now felt that he had overpaid for the voyage. </p> The storm tossed the little boat like a cheap sneaker in an old washing machine. The three drunken fishermen were used to such treatment, of course, but not the tree salesman, who even as a stowaway now felt that he had overpaid for the voyage. <ol> <li> Will the salesman die? </li> <li> What color is the boat? </li> <li> And what about Naomi? </li> </ol> </body> 1. Will the salesman die? 2. What color is the boat? 3. And what about Naomi? Tag Matching Algorithm in Python Code Fragment 6.5: Function for testing if an HTML document has matching tags. 6.2 Queue 6.2.1 The Queue Abstract Data Type 6.2.2 Array-Based Queue Implementation Another fundamental data structure is the queue. It is a close “cousin” of the stack, as a queue is a collection of objects that are inserted and removed according to the first-in, first-out (FIFO) principle. That is, elements can be inserted at any time, but only the element that has been in the queue the longest can be next removed. Applications of Queues • Direct applications • Waiting lists, bureaucracy • Access to shared resources (e.g., printer) • Multiprogramming • Indirect applications • Auxiliary data structure for algorithms • Component of other data structures The Queue ADT • The Queue ADT stores arbitrary objects • Insertions and deletions follow the first-in first-out scheme • Insertions are at the rear of the queue and removals are at the front of the queue • Main queue operations: • enqueue(object): inserts an element at the end of the queue • object dequeue(): removes and returns the element at the front of the queue • Auxiliary queue operations: • object first(): returns the element at the front without removing it • integer len(): returns the number of elements stored • boolean is_empty(): indicates whether no elements are stored • Exceptions • Attempting the execution of dequeue or front on an empty queue throws an EmptyQueueException Example 6.4: The following table shows a series of queue operations and their effects on an initially empty queue Q of integers. 6.2.2 Array-based Queue • Use an array of size N in a circular fashion • Two variables keep track of the front and rear f index of the front element r index immediately past the rear element • Array location r is kept empty normal configuration Q 0 1 2 f r wrapped-around configuration Q 0 1 2 r f Queue Operations • We use the modulo operator (remainder of division) Algorithm size() return (N - f + r) mod N Algorithm isEmpty() return (f = r) Q 0 1 2 f 0 1 2 r r Q f Queue Operations (cont.) • Operation enqueue throws an exception if the array is full • This exception is implementationdependent Algorithm enqueue(o) if size() = N - 1 then throw FullQueueException else Q[r] o r (r + 1) mod N Q 0 1 2 f 0 1 2 r r Q f Queue Operations (cont.) • Operation dequeue throws an exception if the queue is empty • This exception is specified in the queue ADT Algorithm dequeue() if isEmpty() then throw EmptyQueueException else o Q[f] f (f + 1) mod N return o Q 0 1 2 f 0 1 2 r r Q f Queue in Python • Use the following three instance variables: • _data: is a reference to a list instance with a fixed capacity. • _size: is an integer representing the current number of elements stored in the queue (as opposed to the length of the data list). • _front: is an integer that represents the index within data of the first element of the queue (assuming the queue is not empty). Queue in Python (1/3) Queue in Python (2/3) Queue in Python (3/3) Table 6.3: Performance of an array-based implementation of a queue. The bounds for enqueue and dequeue are amortized due to the resizing of the array. The space usage is O(n), where n is the current number of elements in the queue. Application: Round Robin Schedulers • We can implement a round robin scheduler using a queue Q by repeatedly performing the following steps: 1. 2. 3. e = Q.dequeue() Service element e Q.enqueue(e) Queue Dequeue Enqueue Shared Service 6.3 Double-Ended Queues • queue-like data structure that supports insertion and deletion at both the front and the back of the queue. • Such a structure is called a doubleended queue, or deque, which is usually pronounced “deck” • to avoid confusion with the dequeue method of the regular queue ADT, which is pronounced like the abbreviation “D.Q.” • An implementation of a deque class is available in Python’s standard collections module. Deque in Python (1/3) Deque in Python (2/3) Deque in Python (3/3) Summary: Stack, Queue, Deque