• No results found

Partially Ordered Tree Implementation of Priority Queues

Whether we choose sorted or unsorted lists to represent priority queues, we must spend time proportional to n to implement one or the other of INSERT or

DELETEMIN on sets of size n. There is another implementation in which

DELETEMIN and INSERT each require O(logn) steps, a substantial improvement for large n (say n ≥ 100). The basic idea is to organize the elements of the priority queue in a binary tree that is as balanced as possible; an example is in Fig. 4.20. At the lowest level, where some leaves may be missing, we require that all missing leaves are to the right of all leaves that are present on the lowest level.

Most importantly, the tree is partially ordered, meaning that the priority of node v is no greater than the priority of the children of v, where the priority of a node is the priority number of the element stored at the node. Note from Fig. 4.20 that small priority numbers need not appear at higher levels than larger priority numbers. For example, level three has 6 and 8, which are less than the priority number 9 appearing on level 2. However, the parent of 6 and 8 has priority 5, which is, and must be, at least as small as the priorities of its children.

To execute DELETEMIN, we return the minimum-priority element, which, it is easily seen, must be at the root. However, if we simply remove the root, we no longer have a tree. To maintain the property of being a partially ordered tree, as balanced as possible, with leaves at the lowest level as far left as can be, we take the rightmost leaf at the lowest level and temporarily put it at the root. Figure 4.21(a) shows this change from Fig. 4.20. Then we push this element as far down the tree as it will go, by exchanging it with the one of its children having smaller priority, until the element is either at a leaf or at a position where it has priority no larger than either of its

children.

In Fig. 4.21(a) we must exchange the root with its smaller-priority child, which has priority 5. The result is shown in Fig. 4.21(b). The element being pushed down is still larger than its children, with priorities 6 and 8. We exchange it with the smaller of these, 6, to reach the tree of Fig. 4.21(c). This tree has the partially ordered property. In this percolation, if a node v has an element with priority a, if its children have elements with priorities b and c, and if at least one of b and c is smaller than a, then exchanging a with the smaller of b and c results in v having an element whose priority is smaller than either of its children. To prove this, suppose b c. After the exchange, node v acquires b, and its

type celltype = record element: processtype; next: ↑ celltype end; PRIORITYQUEUE = ↑ celltype; { cell pointed to is a list header }

function DELETEMIN ( var A: PRIORITYQUEUE ): ↑ celltype; var

current: ↑ celltype; { cell before one being "scanned" }

lowpriority: integer; { smallest priority found so far } prewinner: ↑ celltype; { cell before one with

element

of smallest priority } begin

if A .next = nil

error('cannot find minimum of empty list') else begin

lowpriority := p(A.next.element);

{ p returns priority of the first element. Note A points to a header cell that does not contain an element } prewinner := A;

current := A.next; while current.next <>

nil do begin

{ compare priorities of current winner and next element }

if p( current.next.element) <

lowpriority then begin

prewinner := current;

lowpriority : = p (current.next. element) end;

current := current.next end;

DELETEMIN := prewinner.next; { return pointer to the winner } prewinner.next :=

prewinner.next.next

{ remove winner from list } end

end; { DELETEMIN }

Fig. 4.19. Linked list priority queue implementation.

children hold a and c. We assumed b c, and we were told that a is larger than at least one of b and c. Therefore b ≤ a surely holds. Thus the insertion procedure outlined above percolates an element down the tree until there

Fig. 4.20. A partially ordered tree.

Let us also observe that DELETEMIN applied to a set of n elements takes O(logn) time. This follows since no path in the tree has more than 1 + logn nodes, and the process of forcing an element down the tree takes a constant time per node. Observe that for any constant c, the quantity c(1+logn) is at most 2clogn for n ≥ 2. Thus

c(1+logn) is O(logn).

Now let us consider how INSERT should work. First, we place the new element as far left as possible on the lowest level, starting a new level if the current lowest level is all filled. Fig. 4.22(a) shows the result of placing an element with priority 4 into Fig. 4.20. If the new element has priority lower than its parent, exchange it with its parent. The new element is now at a position where it is of lower priority than either of its children, but it may also be of lower priority than its parent, in which case we must exchange it with its parent, and repeat the process, until the new element is either at the root or has larger priority than its parent. Figures 4.22(b) and (c) show how 4 moves up by this process.

We could prove that the above steps result in a partially ordered tree. While we shall not attempt a rigorous proof, let us observe that an element with priority a can become the parent of an element with priority b in three ways. (In what follows, we identify an element with its priority.)

1. a is the new element and moves up the tree replacing the old parent of b. Let the old parent of b have priority c. Then a < c, else the exchange would not take place. But c b, since the original tree was partially ordered. Thus a < b. For example in Fig. 4.22(c) 4 became the parent of 6, replacing a parent of larger priority, 5.

2. a was pushed down the tree due to an exchange with the new element. In this case a must have been an ancestor of b in the original partially ordered tree. Thus a b. For example, in Fig. 4.22(c), 5 becomes the

Fig. 4.22. Inserting an element.

parent of elements with priority 8 and 9. Originally, 5 was the parent of the former and the "grandparent" of the latter.

3. b might be the new element, and it moves up to become a child of a. If a > b, then a and b will be exchanged at the next step, so this violation of the

partially ordered property will be removed.

The time to perform an insertion is proportional to the distance up the tree that the new element travels. As for DELETEMIN, we observe that this distance can be no greater than 1 + logn, so both INSERT and DELETEMIN take O(log n) steps.

An Array Implementation of Partially