Anda di halaman 1dari 6

OHSU/OGI (Winter 2009)

CS532

ANALYSIS AND DESIGN OF ALGORITHMS

LECTURE 4

Tree Sort

Suppose a sequence of n items is given. We can sort it using TreeInsert and DeleteMin:

TreeSort Initialize an empty binary search tree T for each input item x TreeInsert(T, x) while T is non-empty output DeleteMin(T )

Recall that TreeInsert and DeleteMin take O(h) time, where h is the height of the tree. If input arrives in such an order that we end up with a balanced tree, the for loop will take O(n log n) time. Similarly, the while loop will take O(n log n) time, and the overall performance of TreeSort will be O(n log n). It is possible to prove that the average running time of TreeSort is indeed O(n log n). Unfortunately, the worst case is (n2 ): if the input arrives in order from largest to smallest, then our tree is a badly ordered list of length n, so that the n calls to DeleteMin will take (n2 ) time. Note the generality of the algorithm TreeSort. It can be used with any data structure that supports operations Insert and DeleteMin. And it will work with complexity O(nf (n) + ng(n)), where f (n) is the complexity of inserting an element and g(n) is the complexity of removing the minimum element.

Packing Trees into Arrays

Trees are packed in level order: the tree

six nine five eight one four seven ten three two

becomes the array

six

nine three five one

ten

two eight four seven

Position of a vertex in the tree determines its index (see it in binary!) in the array:

0001

0010 0100 0101 0110

0011 0111

1000

1001

1010

1011

1100

1101

1110

1111

Basic tree operations implemented in O(1) time: parent(i) = i/2 lef t(i) = 2i right(i) = 2i + 1

A binary tree of height h is complete if every vertex of depth less than h has both children. This tree has 1 + 2 + 22 + + 2h = 2h+1 1 vertices. 2

A full binary tree of height h is almost complete: it can miss only a rightmost part of the bottom level. The vertices in a full tree have positions from 1 to n, where n is a number between 2h and 2h+1 1.

Heaps

Heaps are data structure that provide good performance when we only need operations Insert and DeleteMax. These are the operations needed for priority queuessequences with a highest priority rst out policy. A heap is a full binary tree with the following property: The key at each vertex is greater than the keys at all its descendants. Assume a heap is given as an array H[1..n], together with a variable hpsz to indicate the heap size. Thus, 0 hpsz n, and the values H[i] for i > hpsz are irrelevant.

3.1

Insertion

To add an element to the heap, we rst place it in H[hpsz+ 1]. The only vertices at which the heap propety is possibly violated are the ancestors of hpsz + 1. We just need to go up this ancestry line and place our item in the right place.

PercUp(i) if i > 1 and H[i] > H[parent(i)] exchange H[i] with H[parent(i)] PercUp(parent(i)) Insert(k) if hpsz > n error full heap else H[hpsz + 1] k PercUp(hpsz + 1) hpsz hpsz + 1

There are at most h calls to PercUp when Insert(k) is evaluated. The time for insertion is therefore O(h), which now we know is O(log n).

3.2

Removing the Root

First put H[hpsz] in the roots place. Now the root is the only vertex in H[1 .. hpsz 1] thats smaller than some of its descendants. If we exchange it with its larger child, its still the only possible vertex thats smaller than some of its descendants. But now its at level 1, not at level 0. So we can keep moving the oending vertex down. . .

PercDown(i) if i is not a leaf and H[i] is smaller than H[lef t(i)] or H[right(i)] lef t(i) if H[lef t(i)] > H[right(i)] j right(i) otherwise exchange H[i] with H[j] PercDown(j) DeleteMax if hpsz 0 error empty heap else hpsz hpsz 1 exchange H[1] with H[hpsz] PercDown(1) return H[hpsz] 4

PercDown(i) takes time proportional to the height of i. DeleteMax is just PercDown(1) plus some work independent of the input size; thus, DeleteMax takes O(log n) time.

Building a Heap

If we build a heap of n objects by a sequence of Insert operations, most of the inserts will traverse a path O(log n) deep. (Half of the vertices are in the last two levels!) Thus, the time needed to build the heap this way in the worst case seems to be (n log n). But we can do better if we can assume that all objects are available at the beginning. Then we place them rst in the array H[1..n] in an arbitrary order. Then we heapify H eciently by working bottom-up: Visit the high-level vertices rst and do PercDown on them to put them in place. BuildHeap Store n items in H in any order for i = n down to 1 PercDown(i) There are n recursive calls, and some of them do take O(log n) time. This gives us again O(n log n) for the total building time. But this is a crude estimation and a ner analysis is possible. We havent counted in the fact that many calls to PercDown take little time. Suppose we are building a complete tree of height h. We have 2h vertices of height 0, 2h1 of height 1, 2h2 of height 2, . . . , 2hh of height h. The cost of PercDown(i) is O(l), where l is the height of i. Thus, the total cost is
h h

2
l=0

hl

O(l) = O 2

h l=0

l 2l

To estimate the sum


h

l=0

l 1 2 3 4 5 = + + + + + l 2 2 4 8 16 32 5

note that

l+1 1l+1 l 3 l = < 2l+1 2 l 2l 4 2l holds for l 2. Thus, 2 3 4 5 + + + + 4 8 16 32 2 3 2 3 3 1+ + + 4 4 4 4

<

= 2 The running time of BuildHeap is thus O(2h ). Now if we are building a heap of arbitrary size n, then 2h < n 2h+1 1 and so T (n) T (2h+1 1) = O(2h ) = O(n).

Heap Sort

HeapSort sorts an array H[1..n] in place, and in O(n log n) time.

HeapSort BuildHeap hpsz n while hpsz > 0 hpsz hpsz 1 exchange H[1] with H[hpsz] PercDown(1)

Anda mungkin juga menyukai