{ repeat until S1 or S2 is empty { v1 = pop(S1) v2 = pop(S2) output(min(v1,v2)) if (max(v1,v2) = v1) then push v1 onto S1 else push v2 onto S2 endif } output the remaining nonempty stack by popping its values into the output stream }
Insertion-Sort1(S: stack) { read the input in, pushing each value onto S # n external I/O ops for i = 2 to n do: # Bubble up min or max { for j = 1 to i-2 do: # Get to the test value pop values off S and store them in an array # One pop, two mem I/Os for j = 1 to i-1 do # Bubble-up routine { InsTest(S) # 2 pop, 2 psh, 3 I/O, 1 comp push onto S the last value put into array # one push, two mem I/O } } } InsTest(S : Stack) { v1 = pop(S) # Stack pop v2 = pop(S) # Stack pop if v1 and v2 are not in proper order # Comparison then swap(v1,v2) # Three I/O ops push v2 onto S # Stack push push v1 onto S # Stack push }
Insertion-Sort2(S,T: stack) { read the input in, pushing each value on S # n external I/O ops for i = 2 to n do: # Bubble up the min or max { for j = 1 to i-2 do: # Get to the test value push pop(S) onto T # One push, one pop for j = 1 to i-1 do # Bubble-up routine { InsTest(S) # 2 pop, 2 push, 3 mem I/O, 1 comp push pop(T) onto S # One push, one pop } } } InsTest(S : Stack) { v1 = pop(S) # Stack pop v2 = pop(S) # Stack pop if v1 and v2 are not in proper order # Comparison then swap(v1,v2) # Three I/O ops push v2 onto S # Stack push push v1 onto S # Stack push }
So, all you have to do to find a parent and its child in the heap is to (1) pop off the first i-1 values until you get to the i-th element where the parent is, then (2) pop off the next i-1 values to get to the left child. The popped values can be pushed onto S2 until you do the comparison and swap (if required), then the values can be pushed back onto S1.
ComparePLC(S1,S2,i): { P = i # Parent at i-th location L = 2i # Left child at 2i-th location for j = 1 to P-1 do: # Get to the parent value push pop(S1) onto S2 pv = pop(S1) # Pop parent value off stack for j = 1 to P-1 do: # Get to left-child (LC) value push pop(S1) onto S2 cv = pop(S1) # Pop LC value off stack if pv is not in the proper order with cv # Swap pv and cv if required then swap(pv,cv) push cv onto S1 # Put cv back onto source stack for j = 1 to P-1 do: # Put back second set of values push pop(S2) onto S2 push pv onto S1 # Put pv back onto source stack for j = 1 to P-1 do: # Put back first set of values push pop(S2) onto S1 } # Stacks are ok, S2 is empty
(b) Implement the heap ADT operations we discussed in class
using the stack-based heap you implemented in Part a of this
question.
Answer: The code for INSERT(x) and DELETE(x) can be
expressed in many different ways. Here is one such method for
INSERT, without the heap restoration code, which you can adapt
from Dr. Sahni's book. That code has not been included, to
preserve simplicity of the example. DELETE is symmetrically
expressed.
INSERT(x):
{ while (top(S1) < x) do # Work = 1 comparison
{ pop p from S1 # Work = 2 mem I/O + one list op
push p onto S2 } # Work = 2 mem I/O + one list op
while (not(isEmpty(S2))) do # Work = 1 comparison
{ pop p from S2 # Work = 2 mem I/O + one list op
push p onto S1 } # Work = 2 mem I/O + one list op
}
(b) -- Each call to ComparePLC or ComparePRC (comparing parent with right-child) costs O(n) stack operations. In the best case, there will be no need to sort the heap, so no swaps will be required. But, one will still have to scrabble down through the source stack to find whether or not the heap is properly ordered. This requires O(n2) stack operations for the entire sequence, not O(n log(n)), as in the case of a graph-based heap (implemented, for example, using an adjacency list representation).
Since build-heap requires O(n2) stack operations, it follows that each insertion will require O(n log(n)) operations, instead of the usual O(log n) operations in the graph-based heap. A similar comment holds for deletion from the heap.
(c) -- If INSERT and DELETE are written symmetrically, then they have cost that is the same in terms of Big-Oh notation. In specific cases of insertion and deletion operations, there may be more operations required to restore the heap structure and order properties. On average, however, the complexity is as discussed in Question 5b).
(b) When worst-case input is pushed onto the stack, the stack values have the opposite of the heap-order property. That is, if one wants a min-heap, you get a max-heap when the input is pushed onto the stack.
(c) An example of a best-case input for a min-heap is:
a = (7,6,5,4,3,2,1) ,
which gets pushed onto the stack S1 in reverse order, to yield the min-heap array representation (1,2,3,4,5,6,7) that corresponds to the following diagram:
1 / \ 2 3 / \ / \ 4 5 6 7
An example of the worst case is represented by a = (1,2,3,4,5,6,7), since when pushed onto the stack in reverse, it will form a max-heap (worst case for min-heap construction).
Note: Ask the TAs if you have questions about the homework. You must complete the homework by yourself, but you can work together on general approaches to solving the homework problems. Show your work to get full credit. Any copying will be construed as cheating.Copyright © 1999 by Mark S. Schmalz.