{ 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.