Presentation is loading. Please wait.

Presentation is loading. Please wait.

C++ Classes and Data Structures Jeffrey S. Childs

Similar presentations


Presentation on theme: "C++ Classes and Data Structures Jeffrey S. Childs"— Presentation transcript:

1 C++ Classes and Data Structures Jeffrey S. Childs
Chapter 12 Priority Queues, Trees, and Heaps Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall

2 Priority Queue ADT The data in a priority queue is (conceptually) a queue of elements The “queue” can be thought of as sorted with the largest in front, and the smallest at the end Its physical form, however, may differ from this conceptual view considerably

3 Priority Queue ADT Operations
enqueue, an operation to add an element to the queue dequeue, an operation to take the largest element from the queue an operation to determine whether or not the queue is empty an operation to empty out the queue

4 Another Priority Queue ADT
A priority queue might also be designed to dequeue the element with the minimum value Priority queues are generally not designed to arbitrarily dequeue both minimum and maximum values, whichever the client wants at any particular time We will only consider priority queues that dequeue maximum values (can be easily modified for dequeuing minimum values)

5 Objects as Elements Elements can be objects in priority queues – for example, Employee objects One would overload relational operators in the Employee struct to determine what data member is being considered for maximum value The client may be interested in dequeuing the employee with the maximum age each time Or, the overloaded operator can be written to dequeue the employee with the maximum salary each time

6 Priority Queue Implementation
To implement a priority queue, an array sorted in descending order comes to mind Dequeuing from a sorted array is easy – just get the value at the current front and increment a front index – this is ( 1 ) time However, enqueuing into a sorted array would take some time – the element would have to be inserted into its proper position in the array…

7 Enqueuing an Element … … 211 204 201 81 79 70 69 67 7 5
In this array of elements, each element might be an object, but only the data member considered for maximum value is shown.

8 Enqueuing an Element (cont.)
211 204 201 81 79 70 69 67 7 5 Suppose that element 71 needs to be enqueued.

9 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 67 7 5 Suppose that element 71 needs to be enqueued.

10 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 67 7 5 Suppose that element 71 needs to be enqueued. We could enqueue 71 by using a loop.

11 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 67 7 5 for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

12 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 67 7 5 for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

13 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 67 7 5 i for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

14 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 67 7 5 i for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

15 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 67 7 5 5 i for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

16 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 67 7 5 5 i for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

17 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 67 7 5 5 i for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

18 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 67 7 5 5 i for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

19 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 67 7 7 5 i for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

20 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 67 7 7 5 i This process continues and i eventually becomes 51 for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

21 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 69 20 7 5 i This process continues and i eventually becomes 51 for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

22 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 69 69 20 7 5 i for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

23 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 70 69 20 7 5 i for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

24 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 70 69 20 7 5 i for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

25 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 70 69 20 7 5 i for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

26 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 70 69 20 7 5 i for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

27 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 70 69 20 7 5 i FALSE for ( i = 100; i > 0 && arr[ i - 1 ] < item; i-- ) arr[ i ] = arr[ i – 1 ];

28 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 70 70 69 20 7 5 i Now we can use: arr[ i ] = item; to enqueue the element

29 Enqueuing an Element (cont.)
item: 71 211 204 201 81 79 71 70 69 20 7 5 i Now we can use: arr[ i ] = item; to enqueue the element

30 Enqueuing an Element (cont.)
If we assume that, on average, half the elements in an array need to be shifted to insert an element, then the enqueue for an array is a ( n ) algorithm In summary, when using an array for a priority queue: dequeue is ( 1 ) enqueue (on average) is ( n )

31 Using a Heap to Implement a Priority Queue
An alternative to using a sorted array for a priority queue is to use a heap Here, heap does not mean an area of memory used for dynamic allocation – rather, it is a data structure Enqueue in a heap is a O( lg n ) operation Dequeue in a heap is a O( lg n ) operation

32 Comparing Operations So which is better, the heap or the array?
We often eliminate a data structure that has a high time complexity in a commonly used operation, even if the other operations have very low time complexities In the array, on average, an enqueue-dequeue pair of operations takes ( n ) + ( 1 ) time, but ( 1 ) is absorbed into ( n ), leaving us with an overall time complexity of ( n ) per pair of operations

33 Comparing Operations (cont.)
In the heap, each enqueue-dequeue pair of operations takes O( lg n ) + O( lg n ) time, giving us an overall time complexity of O( lg n ) per pair of operations The heap is usually better, although the array can be good in situations where a group of initial elements are supplied and sorted, then only dequeue operations are performed (no enqueue operations)

34 Trees A heap is a type of tree
In order to understand heaps, we need to discuss trees first We will first limit the discussion to the linked list implementation of trees Trees can be defined with paths A path exists from node A to node B if one can follow a chain of pointers to travel from node A to node B

35 Paths D F A G E B C A set of linked nodes

36 Paths (cont.) D F A G E B C There is one path from A to B

37 Paths (cont.) D F A G E B C There is no path from C to B

38 Paths (cont.) D F A G E B C There is a path from D to B

39 Paths (cont.) D F A G E B There is also a second path from D to B. C

40 Paths (cont.) D F A G E B There is also a second path from D to B. C

41 Definition of Tree A tree is a set of linked nodes, such that there is one and only one path from a unique node (called the root node) to every other node in the tree

42 Example of a Tree root A C B D G E F

43 Cycles There is no cycle (circle of pointers) in a tree
Any linked structure that has a cycle would have more than one path from the root node to another node

44 Example of a Cycle D A B C E

45 Tree Cannot Have a Cycle
D A B Node A cannot be a root node of a tree, because there is more than one path from A to C C E

46 Tree Cannot Have a Cycle (cont.)
D A B C One path from A to C E

47 Tree Cannot Have a Cycle (cont.)
D A B C Another path from A to C (passes through C once) E

48 Example of a Tree In a tree, every pair of linked nodes have a parent-child relationship (the parent is closer to the root) root A C B D G E F

49 Example of a Tree (cont.)
For example, C is a parent of G root A C B D G E F

50 Example of a Tree (cont.)
root A E and F are children of D C B D G E F

51 Example of a Tree (cont.)
The root node is the only node that has no parent. root A C B D G E F

52 Example of a Tree (cont.)
Leaf nodes (or leaves for short) have no children. root A C B D G E F

53 Subtrees A subtree is a part of a tree that is a tree in itself root A
C I K D E F J G H subtree

54 Subtrees (cont.) It normally includes each node reachable from its root. root A B C I K D E F J G H subtree

55 Subtrees (cont.) Even though this looks like a subtree in itself… root
D E F J G H

56 Subtrees (cont.) G and H are reachable from the root. root A B C I K D
J G H

57 Subtrees (cont.) So, normally, G and H would be a part of the subtree.
root A B C I K D E F J G H

58 Binary Trees A binary tree is a tree in which each node can only have up to two children…

59 Not a Binary Tree root A B C I K D E F J G H

60 Example of a Binary Tree
root A B C I K E J G H

61 Example of a Binary Tree (cont.)
The links in a tree are often called edges root A B C I K E J G H

62 Levels root level 0 A level 1 B C level 2 I K E level 3 J G H
The level of a node is the number of edges in the path from the root node to this node

63 Full Binary Tree root A B C D E F G H I J K L M N O
In a full binary tree, each node has two children except for the nodes on the last level, which are leaf nodes

64 Complete Binary Trees A complete binary tree is a binary tree that is either a full binary tree OR a tree that would be a full binary tree but it is missing the rightmost nodes on the last level

65 Complete Binary Trees (cont.)
root A B C D E F G H I

66 Complete Binary Trees (cont.)
root A B C D E F G H I J K L

67 Complete Binary Trees (cont.)
A full binary tree is also a complete binary tree. root A B C D E F G H I J K L M N O

68 Heaps A heap is a complete binary tree in which the value of each node is greater than or equal to the values of its children (if any) Technically, this is called a maxheap In a minheap, the value of each node is less than or equal to the values of its children A maxheap can be easily modified to make a minheap In our discussion, the word “heap” will refer to a maxheap

69 Heaps (cont.) The element stored in each node of a heap can be an object When we talk about the value of a node, we are really talking about some data member of the object that we want to prioritize For example, in employee objects, we may want to prioritize age or salary

70 Example of a Heap root 46 39 28 16 32 24 2 Only the data member is shown that we want to prioritize 14 3 29

71 Example of a Heap (cont.)
root 46 39 28 16 32 24 2 Where is the greatest value in a heap always found? 14 3 29

72 Example of a Heap (cont.)
root 46 39 28 16 32 24 2 Where is the greatest value in a heap always found? 14 3 29

73 Dequeue Dequeuing the object with the greatest value appears to be a ( 1 ) operation However, after removing the object, we must turn the resultant structure into a heap again, for the next dequeue Fortunately, it only takes O( lg n ) time to turn the structure back into a heap again (which is why dequeue in a heap is a O( lg n ) operation

74 Dequeue (cont.) root 46 39 28 16 32 24 2 14 3 29 15 5

75 Dequeue (cont.) root 46 39 28 16 32 24 2 Save the root object in remElement 14 3 29 15 5

76 Dequeue (cont.) root remElement: 46 46 39 28 16 32 24 2
Save the root object in remElement 14 3 29 15 5

77 Dequeue (cont.) root remElement: 46 46 39 28 16 32 24 2 14 3 29 15 5

78 Dequeue (cont.) root remElement: 46 46 39 28 16 32 24 2
Copy object in last node into root object 14 3 29 15 5

79 Dequeue (cont.) root remElement: 46 46 39 28 16 32 24 2
Copy object in last node into root object 14 3 29 15 5

80 Dequeue (cont.) root remElement: 46 5 39 28 16 32 24 2
Copy object in last node into root object 14 3 29 15 5

81 Dequeue (cont.) root remElement: 46 5 39 28 16 32 24 2 14 3 29 15 5

82 Dequeue (cont.) root remElement: 46 5 39 28 16 32 24 2
Remove last node 14 3 29 15 5

83 Dequeue (cont.) root remElement: 46 5 39 28 16 32 24 2
Remove last node 14 3 29 15

84 Dequeue (cont.) root remElement: 46 5 39 28 16 32 24 2 14 3 29 15

85 Dequeue (cont.) root remElement: 46 5 39 28 16 32 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

86 Dequeue (cont.) root remElement: 46 5 Greatest Child 39 28 16 32 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

87 Dequeue (cont.) root remElement: 46 5 Greatest Child 39
39 > 5, so swap 28 16 32 24 2 If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

88 Dequeue (cont.) root remElement: 46 5 39 28 16 32 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

89 Dequeue (cont.) root remElement: 46 39 5 28 16 32 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

90 Dequeue (cont.) root remElement: 46 39 5 28 16 32 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

91 Dequeue (cont.) root remElement: 46 39 5 28 16 32 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

92 Dequeue (cont.) root remElement: 46 39 5 28 16 32 24 2 14 3 29 15

93 Dequeue (cont.) root remElement: 46 39 5 28 16 32 24 2
Notice that 39 is correctly placed – it is guaranteed to be greater than or equal to its two children 14 3 29 15

94 Dequeue (cont.) root remElement: 46 39 5 28 16 32 24 2
It was the greatest child, so it is greater than the other child (28) 14 3 29 15

95 Dequeue (cont.) root remElement: 46 39 5 28 16 32 24 2
It is greater than the element it was swapped with (5), or else we wouldn’t have swapped. 14 3 29 15

96 Dequeue (cont.) root remElement: 46 39 5 28 16 32 24 2
At this point, we repeat the process, using 5 as the parent. 14 3 29 15

97 Dequeue (cont.) root remElement: 46 39 5 28 16 32 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

98 Dequeue (cont.) root remElement: 46 39 5 28 Greatest Child 16 32 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

99 Dequeue (cont.) root remElement: 46 39 5 28 32 > 5, so swap 16 32
24 2 If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

100 Dequeue (cont.) root remElement: 46 39 5 28 16 32 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

101 Dequeue (cont.) root remElement: 46 39 28 5 32 16 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

102 Dequeue (cont.) root remElement: 46 39 28 32 5 16 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

103 Dequeue (cont.) root remElement: 46 39 32 28 16 5 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

104 Dequeue (cont.) root remElement: 46 39 32 28 16 5 24 2 14 3 29 15

105 Dequeue (cont.) root remElement: 46 39 32 28 16 5 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

106 Dequeue (cont.) root remElement: 46 39 32 28 16 5 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15 Greatest Child

107 Dequeue (cont.) root remElement: 46 39 32 28 29 > 5, so swap 16 5
24 2 If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15 Greatest Child

108 Dequeue (cont.) root remElement: 46 39 32 28 16 5 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 29 15

109 Dequeue (cont.) root remElement: 46 39 32 28 16 24 2 5 29
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 15

110 Dequeue (cont.) root remElement: 46 39 32 28 16 24 2 29
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 5 14 3 15

111 Dequeue (cont.) root remElement: 46 39 32 28 16 29 24 2
If the value of the greatest child of 5 is greater than 5, then swap with the greatest child 14 3 5 15

112 Dequeue (cont.) root remElement: 46 39 32 28 16 29 24 2 14 3 5 15

113 Dequeue (cont.) root remElement: 46 39 32 28 16 29 24 2
The final result is a heap! 14 3 5 15

114 Dequeue (cont.) root remElement: 46 39 32 28 16 29 24 2
Sometimes, it is not necessary to swap all the way down through the heap 14 3 5 15

115 Dequeue (cont.) root remElement: 46 39 32 28 16 29 24 2
If 5 would have been greater than or equal to both of its children, we would stop there 14 3 5 15

116 Heapify The process of swapping downwards to form a new heap is called heapifying When, we heapify, it is important that the rest of the structure is a heap, except for the root node that we are starting off with; otherwise, a new heap won’t be formed A loop is used for heapifying; the number of times through the loop is always lg n or less, which gives the O( lg n ) complexity Each time we swap downwards, the number of nodes we can travel to is reduced by approximately half

117 Enqueue root value to enqueue: 37 39 32 28 16 29 24 2 14 3 5 15

118 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2
Create a new node in the last position 14 3 5 15

119 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2
Create a new node in the last position 14 3 5 15

120 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2 14 3 5
15

121 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2
Place the value to enqueue in the last node 14 3 5 15

122 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2
Place the value to enqueue in the last node 14 3 5 15 37

123 Enqueue (cont.) root 39 32 28 16 29 24 2 14 3 5 15 37

124 Enqueue (cont.) root 39 32 28 16 29 24 2 If 37 is larger than its parent, swap 14 3 5 15 37

125 Enqueue (cont.) root 39 32 28 37 > 24, so swap 16 29 24 2
If 37 is larger than its parent, swap 14 3 5 15 37

126 Enqueue (cont.) root 39 32 28 16 29 24 2 14 3 5 15 37

127 Enqueue (cont.) root 39 32 28 16 29 2 24 37 14 3 5 15

128 Enqueue (cont.) root 39 32 28 16 29 2 37 24 14 3 5 15

129 Enqueue (cont.) root 39 32 28 16 29 37 2 14 3 5 15 24

130 Enqueue (cont.) root 39 32 28 16 29 37 2 14 3 5 15 24

131 Enqueue (cont.) root 39 32 28 16 29 37 2 If 37 is larger than its parent, swap 14 3 5 15 24

132 Enqueue (cont.) root 39 37 > 28, so swap 32 28 16 29 37 2
If 37 is larger than its parent, swap 14 3 5 15 24

133 Enqueue (cont.) root 39 32 28 16 29 37 2 14 3 5 15 24

134 Enqueue (cont.) root 39 32 28 37 16 29 2 14 3 5 15 24

135 Enqueue (cont.) root 39 32 28 37 16 29 2 14 3 5 15 24

136 Enqueue (cont.) root 39 32 37 16 29 28 2 14 3 5 15 24

137 Enqueue (cont.) root 39 32 37 16 29 28 2 14 3 5 15 24

138 Enqueue (cont.) root 39 32 37 16 29 28 2 Notice that 37 is guaranteed to be greater than or equal to its children 14 3 5 15 24

139 Enqueue (cont.) root 39 32 37 16 29 28 2 It was greater than the value swapped with (28), or we wouldn’t have swapped… 14 3 5 15 24

140 Enqueue (cont.) root 39 32 37 16 29 28 2 and 28 was greater than the other node (2) or it wouldn’t have been a heap… 14 3 5 15 24

141 Enqueue (cont.) root 39 32 37 16 29 28 2 so 37 must be greater than the other node (2) as well. 14 3 5 15 24

142 Enqueue (cont.) root 39 32 37 16 29 28 2 14 3 5 15 24

143 Enqueue (cont.) root 39 32 37 16 29 28 2 If 37 is larger than its parent, swap 14 3 5 15 24

144 Enqueue (cont.) root 39 37 < 39, so don’t swap 32 37 16 29 28 2
If 37 is larger than its parent, swap 14 3 5 15 24

145 Enqueue (cont.) root 39 32 37 16 29 28 2 14 3 5 15 24

146 Enqueue (cont.) root 39 32 37 16 29 28 2 The result is a heap! 14 3 5
15 24

147 Enqueue (cont.) root 39 32 37 16 29 28 2 Enqueue uses a loop, and it is a O( lg n ) operation (swapping in reverse) 14 3 5 15 24

148 Implementing a Heap Although it is helpful to think of a heap as a linked structure when visualizing the enqueue and dequeue operations, it is often implemented with an array Let’s number the nodes of a heap, starting with 0, going top to bottom and left to right…

149 Implementing a Heap (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 11 9 15 16

150 Heap Properties root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 (left child #) = 2 * (parent #) + 1 11 9 15 16

151 Heap Properties (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 (left child #) = 2 * (parent #) + 1 11 9 15 16

152 Heap Properties (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 (left child #) = 2 * (parent #) + 1 11 9 15 16

153 Heap Properties (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 (left child #) = 2 * (parent #) + 1 11 9 15 16

154 Heap Properties (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 11 9 15 16

155 Heap Properties (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 (right child #) = 2 * (parent #) + 2 11 9 15 16

156 Heap Properties (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 (right child #) = 2 * (parent #) + 2 11 9 15 16

157 Heap Properties (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 (right child #) = 2 * (parent #) + 2 11 9 15 16

158 Heap Properties (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 (right child #) = 2 * (parent #) + 2 11 9 15 16

159 Heap Properties (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 11 9 15 16

160 Heap Properties (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 (parent #) = (child # - 1) / (using integer division) 11 9 15 16

161 Heap Properties (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 (parent #) = (child # - 1) / (using integer division) 11 9 15 16

162 Heap Properties (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 (parent #) = (child # - 1) / (using integer division) 11 9 15 16

163 Heap Properties (cont.)
root 46 39 28 1 2 16 32 24 25 3 4 5 6 14 3 29 15 5 7 18 17 7 8 9 10 11 12 13 14 (parent #) = (child # - 1) / (using integer division) 11 9 15 16

164 Array Implementation These remarkable properties of the heap allow us to place the elements into an array The red numbers on the previous slide correspond to the array indexes

165 Array Implementation (cont.)
46 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 So now, this is our heap. It has no linked nodes, so it is much easier to work with. Let’s dequeue an element. The highest value is stored in the root node (index 0).

166 Array Implementation (cont.)
46 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46

167 Array Implementation (cont.)
46 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 Now we need to move the object at the last node to the root node We need to keep track of the object in the last position of the heap using a heapsize variable remElement: 46

168 Array Implementation (cont.)
46 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 Now we need to move the object at the last node to the root node We need to keep track of the object in the last position of the heap using a heapsize variable remElement: 46 heapsize: 17

169 Array Implementation (cont.)
46 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 Now we can access the object in the last node using elements[ heapsize – 1 ] and assign it to elements[ 0 ] heapsize: 17

170 Array Implementation (cont.)
9 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 Now we can access the object in the last node using elements[ heapsize – 1 ] and assign it to elements[ 0 ] heapsize: 17

171 Array Implementation (cont.)
9 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 Next, decrement the heap size heapsize: 17

172 Array Implementation (cont.)
9 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 Next, decrement the heap size heapsize: 16

173 Array Implementation (cont.)
9 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 The value at index 16 can’t be used anymore; it will be overwritten on the next enqueue remElement: 46 heapsize: 16

174 Array Implementation (cont.)
9 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 Now, we need to find the greatest child of node 0 and compare it to 9. But how do we get the greatest child? remElement: 46 heapsize: 16

175 Array Implementation (cont.)
9 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 By using the formulas we noted earlier (this is why an array can be used)… heapsize: 16

176 Array Implementation (cont.)
9 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 1 (right child #) = 2*(parent #) + 2 = 2 * = 2 heapsize: 16

177 Array Implementation (cont.)
9 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 1 (right child #) = 2*(parent #) + 2 = 2 * = 2 heapsize: 16

178 Array Implementation (cont.)
Greatest Child 9 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 1 (right child #) = 2*(parent #) + 2 = 2 * = 2 heapsize: 16

179 Array Implementation (cont.)
Greatest Child 39 > 9, so swap 9 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 1 (right child #) = 2*(parent #) + 2 = 2 * = 2 heapsize: 16

180 Array Implementation (cont.)
9 39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

181 Array Implementation (cont.)
39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 9 remElement: 46 heapsize: 16

182 Array Implementation (cont.)
39 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 9 remElement: 46 heapsize: 16

183 Array Implementation (cont.)
39 9 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

184 Array Implementation (cont.)
39 9 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 If the greatest child of 9 is greater than 9, then swap heapsize: 16

185 Array Implementation (cont.)
39 9 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 3 (right child #) = 2*(parent #) + 2 = 2 * = 4 heapsize: 16

186 Array Implementation (cont.)
39 9 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 3 (right child #) = 2*(parent #) + 2 = 2 * = 4 heapsize: 16

187 Array Implementation (cont.)
Greatest Child 39 9 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 3 (right child #) = 2*(parent #) + 2 = 2 * = 4 heapsize: 16

188 Array Implementation (cont.)
Greatest Child 32 > 9, so swap 39 9 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 3 (right child #) = 2*(parent #) + 2 = 2 * = 4 heapsize: 16

189 Array Implementation (cont.)
39 9 28 16 32 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

190 Array Implementation (cont.)
9 32 39 28 16 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

191 Array Implementation (cont.)
9 32 39 28 16 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

192 Array Implementation (cont.)
9 32 39 28 16 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

193 Array Implementation (cont.)
32 9 39 28 16 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

194 Array Implementation (cont.)
39 32 28 16 9 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

195 Array Implementation (cont.)
39 32 28 16 9 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 If the greatest child of 9 is greater than 9, then swap heapsize: 16

196 Array Implementation (cont.)
39 32 28 16 9 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 9 (right child #) = 2*(parent #) + 2 = 2 * = 10 heapsize: 16

197 Array Implementation (cont.)
39 32 28 16 9 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 9 (right child #) = 2*(parent #) + 2 = 2 * = 10 heapsize: 16

198 Array Implementation (cont.)
Greatest Child 39 32 28 16 9 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 9 (right child #) = 2*(parent #) + 2 = 2 * = 10 heapsize: 16

199 Array Implementation (cont.)
Greatest Child 29 > 9, so swap 39 32 28 16 9 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 9 (right child #) = 2*(parent #) + 2 = 2 * = 10 heapsize: 16

200 Array Implementation (cont.)
39 32 28 16 9 24 25 14 3 29 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

201 Array Implementation (cont.)
9 29 39 32 28 16 24 25 14 3 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

202 Array Implementation (cont.)
9 29 39 32 28 16 24 25 14 3 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

203 Array Implementation (cont.)
9 29 39 32 28 16 24 25 14 3 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

204 Array Implementation (cont.)
9 29 39 32 28 16 24 25 14 3 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

205 Array Implementation (cont.)
29 9 39 32 28 16 24 25 14 3 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

206 Array Implementation (cont.)
39 32 28 16 29 24 25 14 3 9 15 5 7 18 17 11 9 remElement: 46 heapsize: 16

207 Array Implementation (cont.)
39 32 28 16 29 24 25 14 3 9 15 5 7 18 17 11 9 remElement: 46 If the greatest child of 9 is greater than 9, then swap heapsize: 16

208 Array Implementation (cont.)
39 32 28 16 29 24 25 14 3 9 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 19 heapsize: 16

209 Array Implementation (cont.)
39 32 28 16 29 24 25 14 3 9 15 5 7 18 17 11 9 remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 19 heapsize: 16 19 > heapsize

210 Array Implementation (cont.)
39 32 28 16 29 24 25 14 3 9 15 5 7 18 17 11 9 so 9 must be a leaf node (we can stop) remElement: 46 (left child #) = 2*(parent #) + 1 = 2 * = 19 heapsize: 16

211 Array Implementation (cont.)
39 32 28 16 29 24 25 14 3 9 15 5 7 18 17 11 9 An enqueue is done by placing the new element at elements[ heapsize ], then swapping upwards heapsize: 16

212 Array Implementation (cont.)
39 32 28 16 29 24 25 14 3 9 15 5 7 18 17 11 9 When enqueuing, the parent is always found by using the parent formula: (parent #) = (child # - 1 ) / 2 heapsize: 16

213 Reducing the Work in a Swap
A swap (using simple assignments) cannot just involve two statements: elements[ i ] = elements[ j ]; elements[ j ] = elements[ i ]; On the first line, the value in elements[ i ] is lost; both elements will have the value in elements[ j ]

214 Reducing the Work in a Swap (cont.)
A swap (using simple assignments) would normally involve three statements: temp = elements[ i ]; elements[ i ] = elements[ j ]; elements[ j ] = temp;

215 Reducing the Work in a Swap (cont.)
In an enqueue or a dequeue for a heap, we do not really have to use this three-assignment swap (although it helped to visualize how the enqueue and dequeue process worked) We can save the value we are swapping upwards or downwards Let’s look at an enqueue…

216 Enqueue root value to enqueue: 37 39 32 28 16 29 24 2 14 3 5 15

217 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2
Create a new node in the last position 14 3 5 15

218 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2
Create a new node in the last position 14 3 5 15

219 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2
We just “pretend” that 37 is here 14 3 5 15

220 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2
37 > 24, so we pretend to swap (we just copy 24) 14 3 5 15

221 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2 14 3 5
15

222 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2 24 14 3
5 15

223 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2 14 3 5
15 24

224 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2
We now “pretend” 37 has been placed here 14 3 5 15 24

225 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2
and we compare 37 to 28 to see if we should “swap” again 14 3 5 15 24

226 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2
37 > 28, so we do a one-assignment swap again 14 3 5 15 24

227 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 24 2 14 3 5
15 24

228 Enqueue (cont.) root value to enqueue: 37 39 32 28 28 16 29 24 2 14 3
5 15 24

229 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 28 2 14 3 5
15 24

230 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 28 2
We “pretend” 37 is here 14 3 5 15 24

231 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 28 2
and compare 37 to 39 to see if we should “swap” again 14 3 5 15 24

232 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 28 2
This time we shouldn’t swap… 14 3 5 15 24

233 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 28 2
but we have one final assignment 14 3 5 15 24

234 Enqueue (cont.) root value to enqueue: 37 39 32 28 16 29 28 2
but we have one final assignment 14 3 5 15 24

235 Enqueue (cont.) root value to enqueue: 37 39 32 37 16 29 28 2
but we have one final assignment 14 3 5 15 24

236 Enqueue (cont.) root value to enqueue: 37 39 32 37 16 29 28 2
(we can stop pretending) 14 3 5 15 24

237 Dequeue root 39 32 37 16 29 28 2 The same technique can be used when swapping downward 14 3 5 15 24

238 Parent-Child Formulas
Parent-child formulas can also be sped up: (left child #) = (parent #) << 1 + 1 (right child #) = (left child #) + 1 when finding the greatest child, the left and right children are always found together (parent #) = (child # - 1) >> 1 using the shift operator is the same as integer division

239 PriorityQueue.h 1 #include "Array.h" 2
3 template <class DataType> 4 class PriorityQueue 5 { 6 public: 7 PriorityQueue( ); 8 PriorityQueue( const Array<DataType> & arr ); 9 void enqueue( const DataType & newElement ); 10 bool dequeue( DataType & remElement ); 11 bool isEmpty( ) const; 12 void makeEmpty( );

240 PriorityQueue.h (cont.)
14 private: 15 Array<DataType> elements; 16 int heapsize; 17 inline void heapify( int i ); 18 }; 19 20 #include "PriorityQueue.cpp"

241 Two Constructors There are two constructors in PriorityQueue.h
The first constructor just initializes an empty heap…

242 First Constructor 1 template <class DataType>
2 PriorityQueue<DataType>::PriorityQueue( ) 3 : elements( 2 ), heapsize( 0 ) 4 { 5 }

243 Forming an Initial Heap
The second constructor makes a heap out of an initial array A heap of size n can be made by enqueuing n elements one at a time – but it would take O( n lg n ) time (even though n starts off as small) A faster method can be used to make a heap out of an initial array in ( n ) time The heap will be shown as a linked tree, because it is easier to visualize how the method works – but in actuality, when we use the method, we use it on the array

244 Forming an Initial Heap (cont.)
6 31 5 34 34 11 7 7 12 39 38 5 32 1 34 27 16 Suppose the initial array looks like this. It is not initially a heap, but by rearranging the elements, it will be. We will look at the tree form of this to see why the method works.

245 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 11 7 3 4 5 6 7 12 39 38 5 32 1 34 7 8 9 10 11 12 13 14 27 16 Drawing it this way, we can easily see that the initial array is not a heap 15 16

246 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 11 7 3 4 5 6 7 12 39 38 5 32 1 34 7 8 9 10 11 12 13 14 27 16 We realize that nodes 8 through 16 are subheaps of only one node. 15 16

247 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 11 7 3 4 5 6 7 12 39 38 5 32 1 34 7 8 9 10 11 12 13 14 27 16 We want to heapify starting with the parent of the last leaf node. 15 16

248 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 11 7 3 4 5 6 7 12 39 38 5 32 1 34 7 8 9 10 11 12 13 14 27 16 To find the last leaf node, we use heapsize – 1 (17 – 1 = 16) 15 16

249 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 11 7 3 4 5 6 7 12 39 38 5 32 1 34 7 8 9 10 11 12 13 14 27 16 Then the parent of the last node is (16 – 1) / 2 = 7 15 16

250 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 11 7 3 4 5 6 7 12 39 38 5 32 1 34 7 8 9 10 11 12 13 14 27 16 Heapifying works only if the structure is a heap except for possibly the root. 15 16

251 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 11 7 3 4 5 6 7 12 39 38 5 32 1 34 7 8 9 10 11 12 13 14 27 16 This is true for the structure rooted at index 7, so we can use heapify on it… 15 16

252 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 11 7 3 4 5 6 27 12 39 38 5 32 1 34 7 8 9 10 11 12 13 14 7 16 This is true for the structure rooted at index 7, so we can use heapify on it… 15 16

253 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 11 7 3 4 5 6 27 12 39 38 5 32 1 34 7 8 9 10 11 12 13 14 7 16 Then we decrement index 7 and use heapify again… 15 16

254 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 11 7 3 4 5 6 27 12 39 38 5 32 1 34 7 8 9 10 11 12 13 14 7 16 Then we decrement index 7 and use heapify again… 15 16

255 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 11 34 3 4 5 6 27 12 39 38 5 32 1 7 7 8 9 10 11 12 13 14 7 16 Then we decrement index 7 and use heapify again… 15 16

256 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 11 34 3 4 5 6 27 12 39 38 5 32 1 7 7 8 9 10 11 12 13 14 7 16 This process continues until we heapify at the root 15 16

257 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 11 34 3 4 5 6 27 12 39 38 5 32 1 7 7 8 9 10 11 12 13 14 7 16 15 16

258 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 32 34 3 4 5 6 27 12 39 38 5 11 1 7 7 8 9 10 11 12 13 14 7 16 15 16

259 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 34 32 34 3 4 5 6 27 12 39 38 5 11 1 7 7 8 9 10 11 12 13 14 7 16 15 16

260 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 39 32 34 3 4 5 6 27 12 34 38 5 11 1 7 7 8 9 10 11 12 13 14 7 16 15 16

261 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 39 32 34 3 4 5 6 27 12 34 38 5 11 1 7 7 8 9 10 11 12 13 14 7 16 15 16

262 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 39 32 34 3 4 5 6 27 12 34 38 5 11 1 7 7 8 9 10 11 12 13 14 7 16 already a heap 15 16

263 Forming an Initial Heap (cont.)
root 6 31 5 1 2 34 39 32 34 3 4 5 6 27 12 34 38 5 11 1 7 7 8 9 10 11 12 13 14 7 16 15 16

264 Forming an Initial Heap (cont.)
temp root 6 31 5 1 2 34 39 32 34 3 4 5 6 27 12 34 38 5 11 1 7 7 8 9 10 11 12 13 14 7 16 one-assignment swaps 15 16

265 Forming an Initial Heap (cont.)
root 6 31 34 1 2 34 39 32 7 3 4 5 6 27 12 34 38 5 11 1 5 7 8 9 10 11 12 13 14 7 16 15 16

266 Forming an Initial Heap (cont.)
root 6 31 34 1 2 34 39 32 7 3 4 5 6 27 12 34 38 5 11 1 5 7 8 9 10 11 12 13 14 7 16 15 16

267 Forming an Initial Heap (cont.)
root 6 31 34 1 2 34 39 32 7 3 4 5 6 27 12 34 38 5 11 1 5 7 8 9 10 11 12 13 14 7 16 temp 15 16

268 Forming an Initial Heap (cont.)
root 6 39 34 1 2 34 38 32 7 3 4 5 6 27 12 34 31 5 11 1 5 7 8 9 10 11 12 13 14 7 16 15 16

269 Forming an Initial Heap (cont.)
root 6 39 34 1 2 34 38 32 7 3 4 5 6 27 12 34 31 5 11 1 5 7 8 9 10 11 12 13 14 7 16 15 16

270 Forming an Initial Heap (cont.)
root 6 39 34 1 2 34 38 32 7 3 4 5 6 27 12 34 31 5 11 1 5 7 8 9 10 11 12 13 14 7 16 temp 15 16

271 Forming an Initial Heap (cont.)
root 39 38 34 1 2 34 34 32 7 3 4 5 6 27 12 6 31 5 11 1 5 7 8 9 10 11 12 13 14 7 16 15 16

272 Forming an Initial Heap (cont.)
root 39 38 34 1 2 34 34 32 7 3 4 5 6 27 12 6 31 5 11 1 5 7 8 9 10 11 12 13 14 7 16 The result is a heap 15 16

273 2nd Constructor 6 template <class DataType>
7 PriorityQueue<DataType>::PriorityQueue( const Array<DataType> & arr ) 9 : elements( arr ), heapsize( arr.length( ) ) 10 { 11 for ( int i = ( heapsize - 2 ) >> 1; i >= 0; i-- ) 12 heapify( i ); 13 14 int tryPower = 2; 15 for ( ; tryPower < elements.length( ); tryPower <<= 1 ); 16 17 if ( tryPower != elements.length( ) ) 18 elements.changeSize( tryPower ); 19 }

274 2nd Constructor (cont.) 6 template <class DataType>
7 PriorityQueue<DataType>::PriorityQueue( const Array<DataType> & arr ) 9 : elements( arr ), heapsize( arr.length( ) ) 10 { 11 for ( int i = ( heapsize - 2 ) >> 1; i >= 0; i-- ) 12 heapify( i ); 13 14 int tryPower = 2; 15 for ( ; tryPower < elements.length( ); tryPower <<= 1 ); 16 17 if ( tryPower != elements.length( ) ) 18 elements.changeSize( tryPower ); 19 } ((heapsize – 1) – 1)

275 2nd Constructor (cont.) 6 template <class DataType>
7 PriorityQueue<DataType>::PriorityQueue( const Array<DataType> & arr ) 9 : elements( arr ), heapsize( arr.length( ) ) 10 { 11 for ( int i = ( heapsize - 2 ) >> 1; i >= 0; i-- ) 12 heapify( i ); 13 14 int tryPower = 2; 15 for ( ; tryPower < elements.length( ); tryPower <<= 1 ); 16 17 if ( tryPower != elements.length( ) ) 18 elements.changeSize( tryPower ); 19 } ((heapsize – 1) – 1) index of last node

276 2nd Constructor (cont.) 6 template <class DataType>
7 PriorityQueue<DataType>::PriorityQueue( const Array<DataType> & arr ) 9 : elements( arr ), heapsize( arr.length( ) ) 10 { 11 for ( int i = ( heapsize - 2 ) >> 1; i >= 0; i-- ) 12 heapify( i ); 13 14 int tryPower = 2; 15 for ( ; tryPower < elements.length( ); tryPower <<= 1 ); 16 17 if ( tryPower != elements.length( ) ) 18 elements.changeSize( tryPower ); 19 } index of parent of last node

277 2nd Constructor (cont.) 6 template <class DataType>
7 PriorityQueue<DataType>::PriorityQueue( const Array<DataType> & arr ) 9 : elements( arr ), heapsize( arr.length( ) ) 10 { 11 for ( int i = ( heapsize - 2 ) >> 1; i >= 0; i-- ) 12 heapify( i ); 13 14 int tryPower = 2; 15 for ( ; tryPower < elements.length( ); tryPower <<= 1 ); 16 17 if ( tryPower != elements.length( ) ) 18 elements.changeSize( tryPower ); 19 } makes a heap out of the array

278 2nd Constructor (cont.) 6 template <class DataType>
7 PriorityQueue<DataType>::PriorityQueue( const Array<DataType> & arr ) 9 : elements( arr ), heapsize( arr.length( ) ) 10 { 11 for ( int i = ( heapsize - 2 ) >> 1; i >= 0; i-- ) 12 heapify( i ); 13 14 int tryPower = 2; 15 for ( ; tryPower < elements.length( ); tryPower <<= 1 ); 16 17 if ( tryPower != elements.length( ) ) 18 elements.changeSize( tryPower ); 19 } finds the least power of 2 that is greater than or equal to the array size

279 2nd Constructor (cont.) 6 template <class DataType>
7 PriorityQueue<DataType>::PriorityQueue( const Array<DataType> & arr ) 9 : elements( arr ), heapsize( arr.length( ) ) 10 { 11 for ( int i = ( heapsize - 2 ) >> 1; i >= 0; i-- ) 12 heapify( i ); 13 14 int tryPower = 2; 15 for ( ; tryPower < elements.length( ); tryPower <<= 1 ); 16 17 if ( tryPower != elements.length( ) ) 18 elements.changeSize( tryPower ); 19 } if the array size is not already a power of 2, change it to a power of 2 (helps with maintenance)

280 Enqueue 20 template <class DataType>
21 void PriorityQueue<DataType>::enqueue( const DataType & newElement ) 23 { 24 if ( heapsize == elements.length( ) ) elements.changeSize( elements.length( ) << 1 ); 26 enqueue continued…

281 Enqueue (cont.) i will be used as the current position
27 int i = heapsize; 28 for ( ; (i != 0) && newElement > elements[ (i - 1) >> 1 ]; i = ( i - 1 ) >> 1 ) 30 elements[ i ] = elements[ ( i - 1 ) >> 1 ]; 31 32 elements[ i ] = newElement; 33 heapsize++; 34 }

282 Enqueue (cont.) heapsize – 1 is the index of the last position – we start i at the next position beyond the last position (where we start the enqueue) 27 int i = heapsize; 28 for ( ; (i != 0) && newElement > elements[ (i - 1) >> 1 ]; i = ( i - 1 ) >> 1 ) 30 elements[ i ] = elements[ ( i - 1 ) >> 1 ]; 31 32 elements[ i ] = newElement; 33 heapsize++; 34 }

283 Enqueue (cont.) We are pretending that we placed newElement in this position (newElement is passed in from the client) 27 int i = heapsize; 28 for ( ; (i != 0) && newElement > elements[ (i - 1) >> 1 ]; i = ( i - 1 ) >> 1 ) 30 elements[ i ] = elements[ ( i - 1 ) >> 1 ]; 31 32 elements[ i ] = newElement; 33 heapsize++; 34 }

284 Enqueue (cont.) This is the parent of the current position.
27 int i = heapsize; 28 for ( ; (i != 0) && newElement > elements[ (i - 1) >> 1 ]; i = ( i - 1 ) >> 1 ) 30 elements[ i ] = elements[ ( i - 1 ) >> 1 ]; 31 32 elements[ i ] = newElement; 33 heapsize++; 34 }

285 Enqueue (cont.) We compare newElement with the parent value…
27 int i = heapsize; 28 for ( ; (i != 0) && newElement > elements[ (i - 1) >> 1 ]; i = ( i - 1 ) >> 1 ) 30 elements[ i ] = elements[ ( i - 1 ) >> 1 ]; 31 32 elements[ i ] = newElement; 33 heapsize++; 34 }

286 Enqueue (cont.) and do a one-assignment swap if newElement is greater
27 int i = heapsize; 28 for ( ; (i != 0) && newElement > elements[ (i - 1) >> 1 ]; i = ( i - 1 ) >> 1 ) 30 elements[ i ] = elements[ ( i - 1 ) >> 1 ]; 31 32 elements[ i ] = newElement; 33 heapsize++; 34 }

287 Enqueue (cont.) Then, the current position becomes the parent of the current position 27 int i = heapsize; 28 for ( ; (i != 0) && newElement > elements[ (i - 1) >> 1 ]; i = ( i - 1 ) >> 1 ) 30 elements[ i ] = elements[ ( i - 1 ) >> 1 ]; 31 32 elements[ i ] = newElement; 33 heapsize++; 34 }

288 Enqueue (cont.) Afterwards, we compare newElement with the parent of the new current position 27 int i = heapsize; 28 for ( ; (i != 0) && newElement > elements[ (i - 1) >> 1 ]; i = ( i - 1 ) >> 1 ) 30 elements[ i ] = elements[ ( i - 1 ) >> 1 ]; 31 32 elements[ i ] = newElement; 33 heapsize++; 34 }

289 Enqueue (cont.) When the loop stops, i is either 0 (the root)…
27 int i = heapsize; 28 for ( ; (i != 0) && newElement > elements[ (i - 1) >> 1 ]; i = ( i - 1 ) >> 1 ) 30 elements[ i ] = elements[ ( i - 1 ) >> 1 ]; 31 32 elements[ i ] = newElement; 33 heapsize++; 34 }

290 Enqueue (cont.) or newElement (which we pretend is at the current position i) is less than or equal to its parent 27 int i = heapsize; 28 for ( ; (i != 0) && newElement > elements[ (i - 1) >> 1 ]; i = ( i - 1 ) >> 1 ) 30 elements[ i ] = elements[ ( i - 1 ) >> 1 ]; 31 32 elements[ i ] = newElement; 33 heapsize++; 34 }

291 Enqueue (cont.) Either way, we found the place to put newElement
27 int i = heapsize; 28 for ( ; (i != 0) && newElement > elements[ (i - 1) >> 1 ]; i = ( i - 1 ) >> 1 ) 30 elements[ i ] = elements[ ( i - 1 ) >> 1 ]; 31 32 elements[ i ] = newElement; 33 heapsize++; 34 }

292 Enqueue (cont.) Then, since we enqueued, heapsize is increased by one
27 int i = heapsize; 28 for ( ; (i != 0) && newElement > elements[ (i - 1) >> 1 ]; i = ( i - 1 ) >> 1 ) 30 elements[ i ] = elements[ ( i - 1 ) >> 1 ]; 31 32 elements[ i ] = newElement; 33 heapsize++; 34 }

293 Enqueue (cont.) Notice that this is an overloaded operator for elements that are objects. 27 int i = heapsize; 28 for ( ; (i != 0) && newElement > elements[ (i - 1) >> 1 ]; i = ( i - 1 ) >> 1 ) 30 elements[ i ] = elements[ ( i - 1 ) >> 1 ]; 31 32 elements[ i ] = newElement; 33 heapsize++; 34 }

294 Dequeue 35 template <class DataType>
36 bool PriorityQueue<DataType>::dequeue( DataType & remElement ) 38 { 39 if ( !heapsize ) 40 return false; 41 remElement = elements[ 0 ]; 42 heapsize--; 43 elements[ 0 ] = elements[ heapsize ]; 44 heapify( 0 ); dequeue continued…

295 Dequeue (cont.) 45 int trysize = elements.length( );
46 while ( ( heapsize <= trysize >> 2 ) && trysize > 2 ) 47 trysize >>= 1; 48 49 if ( trysize < elements.length( ) ) { 50 try { 51 elements.changeSize( trysize ); 52 } 53 catch ( ... ) {} 54 } 55 56 return true; 57 }

296 isEmpty 58 template <class DataType>
59 bool PriorityQueue<DataType>::isEmpty( ) const 60 { 61 return !heapsize; 62 }

297 makeEmpty 63 template <class DataType>
64 void PriorityQueue<DataType>::makeEmpty( ) 65 { 66 heapsize = 0; 67 try { 68 elements.changeSize( 2 ); 69 } 70 catch( ... ) { } 71 }

298 Heapify 72 template <class DataType>
73 inline void PriorityQueue<DataType>::heapify( int i ) 74 { 75 int leftChild, rightChild, largest; 76 bool stop = false; 77 78 DataType temp = elements[ i ]; 79 80 leftChild = (i << 1) + 1; heapify continued…

299 Heapify (cont.) 81 while ( leftChild < heapsize && !stop ) {
82 rightChild = leftChild + 1; 83 largest = ( rightChild == heapsize )? leftChild : (( elements[leftChild] > elements[rightChild])? 85 leftChild : rightChild ); 86 if ( elements[ largest ] > temp ) { 87 elements[ i ] = elements[ largest ]; 88 i = largest; 89 leftChild = (i << 1) + 1; 90 } 91 else 92 stop = true; 93 } 94 elements[ i ] = temp; 95 }

300 Heapify (cont.) 81 while ( leftChild < heapsize && !stop ) { 82 rightChild = leftChild + 1; 83 largest = ( rightChild == heapsize )? leftChild : (( elements[leftChild] > elements[rightChild])? 85 leftChild : rightChild ); 86 if ( elements[ largest ] > temp ) { 87 elements[ i ] = elements[ largest ]; 88 i = largest; 89 leftChild = (i << 1) + 1; 90 } 91 else 92 stop = true; 93 } 94 elements[ i ] = temp; 95 } We are careful that the client does not need to overload more than one operator for the class

301 Linked Heap If we have a large element size, we might want to consider conserving memory with a linked heap should have the same time complexities as the array-based heap

302 Dequeue Requirements left and right pointers in a node, so we can get the children for swapping a pointer to the last node in the heap, which needs to be maintained (updated) in ( 1 ) time

303 Enqueue Requirements a parent pointer in a node, for swapping upwards if necessary a ( 1 ) method of finding the place to put the initial node

304 List through the Heap We work with the end of the array when enqueuing or dequeuing We can work with the end of a linked list instead

305 List Through the Heap (cont.)
shown in red A B C D E F G H I J K L M N O

306 Embedded Heap This isn’t a heap now, because it isn’t even a tree
we have cycles We can say there is an “embedded heap” in this data structure

307 Required Pointers We’ll need to maintain a pointer at the end of the list called “last”, so we know where we’re supposed to form a new node (for the enqueue) and remove a node (for the dequeue) We’ll also need a pointer to the last parent, so we know which parent to attach a new node to

308 Adding New Nodes A lastParent B C D E last

309 Adding New Nodes (cont.)
lastParent B C D E F last

310 Adding New Nodes (cont.)
lastParent B C D E F last

311 Adding New Nodes (cont.)
lastParent B C D E F last

312 Adding New Nodes (cont.)
lastParent B C D E F G last

313 Adding New Nodes (cont.)
lastParent B C D E F G last

314 Adding New Nodes (cont.)
lastParent B C D E F G last

315 Adding New Nodes (cont.)
lastParent B C D E F G lastParent = lastParent->next last

316 Adding New Nodes (cont.)
lastParent B C D E F G lastParent = lastParent->next last

317 Adding New Nodes (cont.)
lastParent B C D E F G last

318 Adding New Nodes (cont.)
lastParent B C D E F G last H

319 Adding New Nodes (cont.)
lastParent B C D E F G H last

320 Adding New Nodes (cont.)
lastParent B C D E F G H last

321 Removing Nodes When we remove a node, we’ll have to bring the last pointer back one node If the list through the heap is a singly-linked list, it might not be easy to find the previous node to bring the “last” pointer back to…

322 Removing Nodes (cont.) A B C lastParent D E F G node to remove H I J K

323 Removing Nodes (cont.) If the list through the heap is doubly-linked, it’s easy to find the node to set “last” to…

324 Removing Nodes (cont.) A B C lastParent D E F G node to remove H I J K

325 Removing Nodes (cont.) Using the doubly-linked list, we can also bring lastParent back one node when we need to

326 Node Struct We now have five pointers in a node:
template <class DataType> struct PQNode { DataType info; PQNode<DataType> *left; PQNode<DataType> *right; PQNode<DataType> *parent; PQNode<DataType> *back; PQNode<DataType> *next; };

327 Time Considerations Every time we need to add or remove a node, we’ll need to set a number of pointers In the array-based heap, however, we’d be copying a couple of elements on the average enqueue or dequeue (the average for array expansion / contraction) For large element sizes, it is still worth it

328 Memory Considerations
If an element size is 20 bytes, 50% of the memory in the linked (embedded) heap is wasted If an element size is 1980 bytes, 1% of the memory in the linked (embedded) heap is wasted For large element sizes, it is a worthwhile data structure to consider

329 Avoiding Special Cases
We can avoid handling special cases involving the root by using a “root header node” similar to the header node in the linked list The actual root node will branch off as a single child of the root header Should the actual root branch from the left or right side of the root header?

330 Position of Actual Root
The root pointer, last pointer, and lastParent pointer will start off pointing to the root header We move the lastParent pointer forward after a right child has been attached to its node Therefore, the actual root should branch off the right side of the root header…

331 Starting it Off last root lastParent root header
an empty heap – heap is empty when root == last

332 Starting it Off (cont.) last root lastParent root header
an element is enqueued – “actual root” is inserted A

333 Starting it Off (cont.) last root lastParent root header A

334 Starting it Off (cont.) root lastParent root header last A

335 Starting it Off (cont.) root lastParent root header last A
Since a node has been inserted to the right of the lastParent node, it is time to move the lastParent

336 Starting it Off (cont.) root root header last lastParent A
Since a node has been inserted to the right of the lastParent node, it is time to move the lastParent

337 Starting it Off (cont.) root root header last lastParent A
Now, we are in a position to insert to the left and right of this node

338 Starting it Off (cont.) root root header last lastParent A B

339 Starting it Off (cont.) root root header lastParent A last B

340 Starting it Off (cont.) root root header lastParent A last B

341 Starting it Off (cont.) root root header lastParent A last B C

342 Starting it Off (cont.) root root header lastParent A last B C

343 Starting it Off (cont.) root root header lastParent A last B C

344 Starting it Off (cont.) root root header A last lastParent B C

345 Starting it Off (cont.) root root header A last lastParent etc. B C

346 PriorityQueue.h We still need Array.h, since the client will pass an Array into the second constructor 1 #include "Array.h" 2 3 template <class DataType> 4 struct PQNode { 5 DataType info; 6 PQNode<DataType> *left; 7 PQNode<DataType> *right; 8 PQNode<DataType> *parent; 9 PQNode<DataType> *back; 10 PQNode<DataType> *next; 11 }; PriorityQueue.h continued…

347 PriorityQueue.h (cont.)
12 template <class DataType> 13 class PriorityQueue 14 { 15 public: 16 PriorityQueue( ); 17 PriorityQueue( Array<DataType> & arr ); 18 PriorityQueue( const PriorityQueue<DataType> & appq ); 19 ~PriorityQueue( ); 20 PriorityQueue<DataType> & operator =( const PriorityQueue<DataType> & rpq );

348 PriorityQueue.h (cont.)
22 void enqueue( const DataType & newElement ); 23 bool dequeue( DataType & deqElement ); 24 bool isEmpty(); 25 void makeEmpty();

349 PriorityQueue.h (cont.)
26 private: 27 PQNode<DataType> rootNode; 28 PQNode<DataType> *root; 29 PQNode<DataType> *last; 30 PQNode<DataType> *lastParent; 31 bool left; 32 inline void insertNode( const DataType & inf ); 33 inline void heapify( PQNode<DataType> *current ); 34 inline void deepCopy( const PriorityQueue<DataType> & original ); 36 }; 37 38 #include "PriorityQueue.cpp"

350 PriorityQueue.h (cont.)
Used to determine which side of the lastParent node to insert on… 26 private: 27 PQNode<DataType> rootNode; 28 PQNode<DataType> *root; 29 PQNode<DataType> *last; 30 PQNode<DataType> *lastParent; 31 bool left; 32 inline void insertNode( const DataType & inf ); 33 inline void heapify( PQNode<DataType> *current ); 34 inline void deepCopy( const PriorityQueue<DataType> & original ); 36 }; 37 38 #include "PriorityQueue.cpp"

351 PriorityQueue.h (cont.)
26 private: 27 PQNode<DataType> rootNode; 28 PQNode<DataType> *root; 29 PQNode<DataType> *last; 30 PQNode<DataType> *lastParent; 31 bool left; 32 inline void insertNode( const DataType & inf ); 33 inline void heapify( PQNode<DataType> *current ); 34 inline void deepCopy( const PriorityQueue<DataType> & original ); 36 }; 37 38 #include "PriorityQueue.cpp" and also when to move the lastParent pointer

352 First Constructor 1 template <class DataType>
2 PriorityQueue<DataType>::PriorityQueue( ) 3 { 4 last = lastParent = root = &rootHeader; 5 root->next = NULL; 6 left = false; 7 }

353 Second Constructor 8 template <class DataType>
9 PriorityQueue<DataType>::PriorityQueue( Array<DataType> & arr ) 11 { 12 last = lastParent = root = &rootHeader; 13 left = false; 14 15 for ( int i = 0; i < arr.length( ); i++ ) 16 insertNode( arr[ i ] ); 17 18 for ( PQNode<DataType> *current = last->parent; 19 current != root; current = current->back ) 20 heapify( current ); 21 }

354 Second Constructor 8 template <class DataType>
9 PriorityQueue<DataType>::PriorityQueue( Array<DataType> & arr ) 11 { 12 last = lastParent = root = &rootHeader; 13 left = false; 14 15 for ( int i = 0; i < arr.length( ); i++ ) 16 insertNode( arr[ i ] ); 17 18 for ( PQNode<DataType> *current = last->parent; 19 current != root; current = current->back ) 20 heapify( current ); 21 } Makes the “embedded tree” (just inserts)

355 Second Constructor 8 template <class DataType>
9 PriorityQueue<DataType>::PriorityQueue( Array<DataType> & arr ) 11 { 12 last = lastParent = root = &rootHeader; 13 left = false; 14 15 for ( int i = 0; i < arr.length( ); i++ ) 16 insertNode( arr[ i ] ); 17 18 for ( PQNode<DataType> *current = last->parent; 19 current != root; current = current->back ) 20 heapify( current ); 21 } Makes an embedded heap out of the embedded tree

356 Second Constructor 8 template <class DataType>
9 PriorityQueue<DataType>::PriorityQueue( Array<DataType> & arr ) 11 { 12 last = lastParent = root = &rootHeader; 13 left = false; 14 15 for ( int i = 0; i < arr.length( ); i++ ) 16 insertNode( arr[ i ] ); 17 18 for ( PQNode<DataType> *current = last->parent; 19 current != root; current = current->back ) 20 heapify( current ); 21 } Remember that root points to the root header

357 Copy Constructor and Destructor
22 template <class DataType> 23 PriorityQueue<DataType>::PriorityQueue( const PriorityQueue<DataType> & appq ) 25 { 26 deepCopy( appq ); 27 } 28 29 template <class DataType> 30 PriorityQueue<DataType>::~PriorityQueue( ) 31 { 32 makeEmpty( ); 33 }

358 Overloaded Assignment Operator
34 template <class DataType> 35 PriorityQueue<DataType> & PriorityQueue<DataType>:: 36 operator =( const PriorityQueue<DataType> & rpq ) 37 { 38 if ( this == &rpq ) 39 return *this; 40 makeEmpty( ); 41 deepCopy( rpq ); 42 return *this; 43 }

359 Enqueue 44 template <class DataType>
45 void PriorityQueue<DataType>::enqueue( const DataType & newElement) 47 { 48 insertNode( newElement ); Places a new node at the end of the heap enqueue continued…

360 Enqueue (cont.) reheap upwards using one-assignment swaps
49 PQNode<DataType> *current = last, 50 *parent = current->parent; 51 while ( parent != root && newElement > parent->info ) { 52 current->info = parent->info; 53 current = parent; 54 parent = current->parent; 55 } 56 57 current->info = newElement; 58 }

361 Dequeue 59 template <class DataType>
60 bool PriorityQueue<DataType>::dequeue( DataType & deqElement ) 62 { 63 if ( root == last ) 64 return false; 65 66 PQNode<DataType> *current = root->right; 67 deqElement = current->info; 68 current->info = last->info; dequeue continued…

362 Dequeue (cont.) 69 if (left) { 70 lastParent = lastParent->back;
71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; Code to remove the last node

363 Dequeue (cont.) 69 if (left) { 70 lastParent = lastParent->back;
71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; True if the next node to be inserted will be the left child of the lastParent node…

364 Dequeue (cont.) 69 if (left) { 70 lastParent = lastParent->back;
71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; but we are removing a node, so we have to move lastParent back

365 Dequeue (cont.) 69 if (left) { 70 lastParent = lastParent->back;
71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; We’ll use this pointer convention to show how the code works parent back next left right

366 Dequeue (cont.) root 69 if (left) {
70 lastParent = lastParent->back; 71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; lastParent last

367 Dequeue (cont.) root 69 if (left) {
70 lastParent = lastParent->back; 71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; lastParent last

368 Dequeue (cont.) root 69 if (left) {
70 lastParent = lastParent->back; 71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; last lastParent

369 Dequeue (cont.) root 69 if (left) {
70 lastParent = lastParent->back; 71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; last lastParent

370 Dequeue (cont.) root 69 if (left) {
70 lastParent = lastParent->back; 71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; last lastParent

371 Dequeue (cont.) root 69 if (left) {
70 lastParent = lastParent->back; 71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; last lastParent

372 Dequeue (cont.) root 69 if (left) {
70 lastParent = lastParent->back; 71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; lastParent last

373 Dequeue (cont.) root 69 if (left) {
70 lastParent = lastParent->back; 71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; lastParent last

374 Dequeue (cont.) root 69 if (left) {
70 lastParent = lastParent->back; 71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; lastParent last

375 Dequeue (cont.) root 69 if (left) {
70 lastParent = lastParent->back; 71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; lastParent last

376 Dequeue (cont.) root 69 if (left) {
70 lastParent = lastParent->back; 71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; lastParent last

377 Dequeue (cont.) 69 if (left) { 70 lastParent = lastParent->back;
71 lastParent->right = NULL; 72 } 73 else 74 lastParent->left = NULL; 75 last = last->back; 76 delete last->next; 77 last->next = NULL; dequeue continued…

378 Dequeue (cont.) toggle left whenever we have to enqueue or dequeue (it was done in the insertNode function for enqueue) 78 left = !left; 79 80 if ( root != last ) 81 heapify( current ); 82 83 return true; 84 }

379 Dequeue (cont.) current was set to the “actual root” previously
78 left = !left; 79 80 if ( root != last ) 81 heapify( current ); 82 83 return true; 84 }

380 Dequeue (cont.) if the heap isn’t empty, the last step of dequeue is to heapify 78 left = !left; 79 80 if ( root != last ) 81 heapify( current ); 82 83 return true; 84 }

381 isEmpty 85 template <class DataType>
86 bool PriorityQueue<DataType>::isEmpty() 87 { 88 return root == last; 89 }

382 makeEmpty 90 template <class DataType>
91 void PriorityQueue<DataType>::makeEmpty() 92 { 93 while ( root != last ) { 94 lastParent = last->back; 95 delete last; 96 last = lastParent; 97 } 98 99 root->next = NULL; 100 left = false; 101 } We move back through the doubly-linked list, freeing each last node along the way

383 makeEmpty (cont.) 90 template <class DataType>
91 void PriorityQueue<DataType>::makeEmpty() 92 { 93 while ( root != last ) { 94 lastParent = last->back; 95 delete last; 96 last = lastParent; 97 } 98 99 root->next = NULL; 100 left = false; 101 } When done, we want the last and lastParent pointers to point to the root header

384 makeEmpty (cont.) 90 template <class DataType>
91 void PriorityQueue<DataType>::makeEmpty() 92 { 93 while ( root != last ) { 94 lastParent = last->back; 95 delete last; 96 last = lastParent; 97 } 98 99 root->next = NULL; 100 left = false; 101 } last points to the root header when the loop stops…

385 makeEmpty (cont.) 90 template <class DataType>
91 void PriorityQueue<DataType>::makeEmpty() 92 { 93 while ( root != last ) { 94 lastParent = last->back; 95 delete last; 96 last = lastParent; 97 } 98 99 root->next = NULL; 100 left = false; 101 } which means that lastParent also points to the root header

386 insertNode 102 template <class DataType>
103 inline void PriorityQueue<DataType>::insertNode( const DataType & inf ) 105 { We’ll see how the body of insertNode works on the following slides…

387 insertNode (cont.) root
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } lastParent last

388 insertNode (cont.) root
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } lastParent last

389 insertNode (cont.) root 107 last->next->back = last; lastParent
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } lastParent last

390 insertNode (cont.) root 107 last->next->back = last; lastParent
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } lastParent last

391 insertNode (cont.) root 108 last = last->next; lastParent last
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } lastParent last

392 insertNode (cont.) root 108 last = last->next; last lastParent
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } last lastParent

393 insertNode (cont.) root
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } last lastParent

394 insertNode (cont.) root
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } last lastParent

395 insertNode (cont.) root 110 last->parent = lastParent; last
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } last lastParent

396 insertNode (cont.) root 110 last->parent = lastParent; last
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } last lastParent

397 insertNode (cont.) root 111 if (left) last lastParent
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } last lastParent

398 insertNode (cont.) root 113 else { last lastParent
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } last lastParent

399 insertNode (cont.) root 114 lastParent->right = last; last
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } last lastParent

400 insertNode (cont.) root 114 lastParent->right = last; last
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } last lastParent

401 insertNode (cont.) root 115 lastParent = lastParent->next; last
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } last lastParent

402 insertNode (cont.) root 115 lastParent = lastParent->next;
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } lastParent last

403 insertNode (cont.) root lastParent 117 last->info = inf; last
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } lastParent last

404 insertNode (cont.) root lastParent 117 last->info = inf; last
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } lastParent last inf was passed in as a parameter

405 insertNode (cont.) root lastParent 118 left = !left; last
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } lastParent last

406 insertNode (cont.) root lastParent last
106 last->next = new PQNode<DataType>(); 107 last->next->back = last; 108 last = last->next; 109 last->left = last->right = last->next = NULL; 110 last->parent = lastParent; 111 if (left) lastParent->left = last; 113 else { lastParent->right = last; lastParent = lastParent->next; 116 } 117 last->info = inf; 118 left = !left; 119 } lastParent last

407 Heapify 120 template <class DataType>
121 inline void PriorityQueue<DataType>::heapify( PQNode<DataType> *current ) 123 { 124 DataType temp = current->info; 125 126 PQNode<DataType> *leftc = current->left, *rightc = current->right, *largest; 128 largest = (rightc == NULL)? leftc : 129 ((leftc->info > rightc->info)? leftc : rightc ); for one-assignment swaps heapify continued…

408 Heapify (cont.) 130 while ( (leftc != NULL) && largest->info > temp ) { 131 current->info = largest->info; 132 current = largest; 133 leftc = current->left; 134 rightc = current->right; 135 largest = (rightc == NULL)? leftc : ((leftc->info > rightc->info)? leftc : rightc ); } 138 139 current->info = temp; 140 } the one-assignment swap

409 Heapify (cont.) 130 while ( (leftc != NULL) && largest->info > temp ) { 131 current->info = largest->info; 132 current = largest; 133 leftc = current->left; 134 rightc = current->right; 135 largest = (rightc == NULL)? leftc : ((leftc->info > rightc->info)? leftc : rightc ); } 138 139 current->info = temp; 140 } largest points to largest child, so move current down to it

410 Heapify (cont.) 130 while ( (leftc != NULL) && largest->info > temp ) { 131 current->info = largest->info; 132 current = largest; 133 leftc = current->left; 134 rightc = current->right; 135 largest = (rightc == NULL)? leftc : ((leftc->info > rightc->info)? leftc : rightc ); } 138 139 current->info = temp; 140 }

411 deepCopy 141 template <class DataType>
142 inline void PriorityQueue<DataType>::deepCopy( const PriorityQueue<DataType> & original ) 144 { 145 last = lastParent = root = &rootHeader; 146 root->next = NULL; 147 left = false; 148 149 PQNode<DataType> *originalptr = original.root->next; 150 for ( ; originalptr != NULL; originalptr = originalptr->next ) 153 insertNode( originalptr->info ); 154 }


Download ppt "C++ Classes and Data Structures Jeffrey S. Childs"

Similar presentations


Ads by Google