implementing heaps bounded priority queues
play

Implementing Heaps Bounded Priority Queues Priority queues : - PowerPoint PPT Presentation

Implementing Heaps Bounded Priority Queues Priority queues : Bounded Priority Queue Interface a type of work list that // typedef void* elem; // Decided by client typedef bool has_higher_priority_fn (elem e1, elem e2); o stores


  1. Implementing Heaps

  2. Bounded Priority Queues  Priority queues : Bounded Priority Queue Interface a type of work list that // typedef void* elem; // Decided by client typedef bool has_higher_priority_fn (elem e1, elem e2); o stores elements // typedef ______* pq_t; o gives back the one with the bool pq_empty(pq_t Q) /*@requires Q != NULL; @*/ ; highest priority bool pq_full(pq_t Q) /*@requires Q != NULL; @*/ ;  How big? pq_t pq_new(int capacity, has_higher_priority_fn* prio) /*@requires capacity > 0 && prio != NULL; @*/ o unbounded /*@ensures \result != NULL && pq_empty(\result); @*/ ; o bounded void pq_add(pq_t Q, elem e) /*@requires Q != NULL && !pq_full(Q) && e != NULL; @*/ /*@ensures !pq_empty(Q); @*/ ; elem pq_rem (pq_t Q) /*@requires Q != NULL && !pq_empty(Q); @*/ /*@ensures \result != NULL && !pq_full(Q); @*/ ; elem pq_peek (pq_t Q) /*@requires Q != NULL && !pq_empty(Q); @*/ /*@ensures \result != NULL && !pq_empty(Q); @*/ ; 1

  3. Priority Queues A priority queue viewed as a heap implemented as an array 1 2 2 3 2 4 4 7 8 9 4 8 4 5 6 7 4 9 0 1 2 3 4 5 6 7 8 9 2 4 8 7 4 9 2

  4. Heaps Invariants higher priority 1. Shape invariant 2. Ordering invariant o The priority of a child is lower than point of view of child or equal to the priority of its parent or equivalently o The priority of a parent is higher than point of view of parent or equal to the priority of its children 3

  5. Heap Operations  Insertion o place the new element in the leftmost open position in the last level to satisfy O(log n) the shape invariant o sift up to restore the ordering invariant  Removal o replace the root with the element in the rightmost filled position on the last level O(log n) to satisfy the shape invariant o sift down to restore the ordering invariant Strategy: • maintain the shape invariant • temporarily break and then restore the ordering invariant 4

  6. Implementing Bounded Heaps 5

  7. Concrete Type 0 1 2 3 4 5 6 next limit 2 4 8 7 4 9  The heap data structure needs to store o the array that contains the heap elements o its true size because we sacrifice index 0  that’s capacity + 1 o the position where to add the next element o the priority function typedef struct heap_header heap; struct heap_header { int limit; // == capacity + 1 elem[] data; // \length(data) == limit int next; // 1 <= next && next <= limit has_higher_priority_fn* prior; // != NULL }; 6

  8. Basic Representation Invariants typedef struct heap_header heap; struct heap_header { int limit; // == capacity + 1 elem[] data; // \length(data) == limit int next; // 1 <= next && next <= limit has_higher_priority_fn* prior; // != NULL };  We simply translate the field constraints o and preempt overflow because right child of i is 2i+1 bool is_heap_safe(heap* H) { return H != NULL and 2*(int_max()/2) + 1 == int_max() && 1 < H->limit && H->limit <= int_max()/2 && is_array_expected_length(H->data, H->limit) && 1 <= H->next && H->next <= H->limit && H->prior != NULL; }  This checks that basic heap manipulations are safe 7

  9. Heap Invariants Beyond basic safety, we need to check:  the shape invariant o this is automatic 1 2  elements are stored  level by level 2 3 4 8  from left to right 4 5 6 7 4 9 0 1 2 3 4 5 6 7 8 9 2 4 8 7 4 9  the ordering invariant higher priority 8

  10. typedef struct heap_header heap; struct heap_header { int limit; // == capacity + 1 The Ordering Invariant elem[] data; // \length(data) == limit int next; // 1 <= next && next <= limit has_higher_priority_fn* prior; // != NULL };  The priority of a child is lower than or equal to the priority of its parent  The priority of a parent is higher than or equal to the priority of its children  Let’s introduce an abstraction o Reason about where a node belongs in the tree  not priorities This will also help with the confusion about min-heaps  not arrays  It’s Ok for node e1 to be the parent of e2 if Min-heap version: o e1 has priority higher than or equal to e2 value of e1 ≤ value of e2  but prior tests if a node has strictly higher priority than another o it is not the case that Min-heap version: e2 has strictly higher priority than e1 value of e2 < value of e1 9

  11. typedef struct heap_header heap; struct heap_header { int limit; // == capacity + 1 The Ordering Invariant elem[] data; // \length(data) == limit int next; // 1 <= next && next <= limit has_higher_priority_fn* prior; // != NULL };  It’s Ok for node e1 to be the parent of e2 if o it is not the case that e2 has strictly higher priority than e1 bool ok_above(heap* H, int i1, int i2) H is safe //@requires is_heap_safe(H); //@requires 1 <= i1 && i1 < H->next; i1 and i2 are in bounds i1 and i2 are in bounds //@requires 1 <= i2 && i2 < H->next; { elem e1 = H->data[i1]; elem e2 = H->data[i2]; return !(*H->prior)(e2, e1); } 10

  12. typedef struct heap_header heap; struct heap_header { int limit; // == capacity + 1 The Ordering Invariant elem[] data; // \length(data) == limit int next; // 1 <= next && next <= limit has_higher_priority_fn* prior; // != NULL };  The priority of every child is lower than or equal to the priority of its parent 1 2 o Every parent is Ok above its children 2 3 4 8 4 5 6 7 4 9 bool is_heap_ordered(heap* H) H is safe //@requires is_heap_safe(H); 0 1 2 3 4 5 6 7 8 9 { 2 4 8 7 4 9 for (int child = 2; child < H->next; child++) o The root of the tree is //@loop_invariant 2 <= child && child <= H->next; { at index 1 int parent = child/2; if (!ok_above(H, parent, child))  the first child is at index 2 return false; } return true; o Is this code safe? } 11

  13. typedef struct heap_header heap; struct heap_header { int limit; // == capacity + 1 The Ordering Invariant elem[] data; // \length(data) == limit int next; // 1 <= next && next <= limit has_higher_priority_fn* prior; // != NULL };  Is this code safe? o H->next 1. bool is_heap_ordered(heap* H)  because H != NULL 2. //@requires is_heap_safe(H);  since is_heap_safe(H) 3. { for (int child = 2; child < H->next; child++) 4. o ok_above(H, parent, child) //@loop_invariant 2 <= child && child <= H->next; 5. { 6. int parent = child/2; 7. bool ok_above(heap* H, int i1, int i2) if (!ok_above(H, parent, child)) 8. //@requires is_heap_safe(H); return false; 9. //@requires 1 <= i1 && i1 < H->next; } 10. //@requires 1 <= i2 && i2 < H->next; return true; 11. 12. }  1 <= child && child < H->next  because 2 <= child by line 5  and child < H->next by line 4  1 <= parent && parent < H->next  because parent = child/2 by line 7  and 2 <= child && child < H->next  by lines 4 – 5 and math 12

  14. The Representation Invariant  A value of type heap must satisfy o the basic safety invariants o the shape invariant  automatic o the ordering invariant bool is_heap(heap* H) { return is_heap_safe(H) && is_heap_ordered(H); } 13

  15. Constant-time Operations 14

  16. typedef struct heap_header heap; struct heap_header { int limit; // == capacity + 1 pq_full, pq_empty, pq_peek elem[] data; // \length(data) == limit int next; // 1 <= next && next <= limit has_higher_priority_fn* prior; // != NULL }; bool pq_full(heap* H) We can fill a bounded 1 2 //@requires is_heap(H); heap to the brim { 2 3 return H->next == H->limit; 4 8 O(1) } 4 5 6 7 4 9 bool pq_empty(heap* H) //@requires is_heap(H); 0 1 2 3 4 5 6 7 8 9 { 2 4 8 7 4 9 return H->next == 1; O(1) } elem pq_peek(heap* H) //@requires is_heap(H) && !pq_empty(H); We sacrificed We sacrificed //@ensures is_heap(H) && !pq_empty(H); index 0 index 0 { return H->data[1]; O(1) } 15

  17. typedef struct heap_header heap; struct heap_header { int limit; // == capacity + 1 pq_new elem[] data; // \length(data) == limit int next; // 1 <= next && next <= limit has_higher_priority_fn* prior; // != NULL }; 1 heap* pq_new(int capacity, has_higher_priority_fn* prior) 2 //@requires 0 < capacity && capacity <= int_max()/2 - 1; //@requires prior != NULL; 2 3 4 8 //@ensures is_heap(\result); O(1) { Overflow! Overflow! 4 5 6 7 4 9 heap* H = alloc(heap); H->limit = capacity + 1; H->next = 1; H->data = alloc_array(elem, H->limit); H->prior = prior; 0 1 2 3 4 5 6 7 8 9 2 4 8 7 4 9 return H; } o To preempt overflow, we must have 1 < H->limit && H->limit <= int_max()/2 but H->limit == capacity + 1 o so 0 < capacity && capacity <= int_max()/2 - 1 16

  18. Implementing pq_add 17

Recommend


More recommend