1 module neton.lease.Heap; 2 3 // Any type that implements heap.Interface may be used as a 4 // min-heap with the following invariants (established after 5 // Init has been called or if the data is empty or sorted): 6 // 7 // !_queueLess(j, i) for 0 <= i < _queueLen() and 2*i+1 <= j <= 2*i+2 and j < _queueLen() 8 // 9 // Note that Push and Pop in this interface are for package heap's 10 // implementation to call. To add and remove things from the heap, 11 // use heap.Push and heap.Pop. 12 13 struct Heap(T) 14 { 15 private T _queue; 16 17 // A heap must be initialized before any of the heap operations 18 // can be used. Init is idempotent with respect to the heap invariants 19 // and may be called whenever the heap invariants may have been invalidated. 20 // Its complexity is O(n) where n = _queueLen(). 21 // 22 public void Init(T t) 23 { 24 // heapify 25 _queue = t; 26 auto n = t.Len(); 27 for (int i = n / 2 - 1; i >= 0; i--) 28 { 29 down(i, n); 30 } 31 } 32 33 // Push pushes the element x onto the heap. The complexity is 34 // O(log(n)) where n = _queueLen(). 35 // 36 public void Push(D)(D d) 37 { 38 _queue.Push(d); 39 up(_queue.Len() - 1); 40 } 41 42 // Pop removes the minimum element (according to Less) from the heap 43 // and returns it. The complexity is O(log(n)) where n = _queueLen(). 44 // It is equivalent to Remove(h, 0). 45 // 46 public D Pop(D)() 47 { 48 auto n = _queue.Len() - 1; 49 _queue.Swap(0, n); 50 down(0, n); 51 return _queue.Pop(); 52 } 53 54 // Remove removes the element at index i from the heap. 55 // The complexity is O(log(n)) where n = _queueLen(). 56 // 57 public D Remove(D)(int i) 58 { 59 auto n = _queueLen() - 1; 60 if (n != i) 61 { 62 _queue.Swap(i, n); 63 if (!down(i, n)) 64 { 65 up(i); 66 } 67 } 68 return _queue.Pop(); 69 } 70 71 public D get(D)(int idx) 72 { 73 return _queue.get(idx); 74 } 75 76 public void clear() 77 { 78 _queue.clear(); 79 } 80 // Fix re-establishes the heap ordering after the element at index i has changed its value. 81 // Changing the value of the element at index i and then calling Fix is equivalent to, 82 // but less expensive than, calling Remove(h, i) followed by a Push of the new value. 83 // The complexity is O(log(n)) where n = _queueLen(). 84 public void Fix(int i) 85 { 86 if (!down(i, _queue.Len())) 87 { 88 up(i); 89 } 90 } 91 92 public int length() 93 { 94 return _queue.Len(); 95 } 96 97 private void up(int j) 98 { 99 while (1) 100 { 101 auto i = (j - 1) / 2; // parent 102 if (i == j || !_queue.Less(j, i)) 103 { 104 break; 105 } 106 _queue.Swap(i, j); 107 j = i; 108 } 109 } 110 111 private bool down(int i0, int n) 112 { 113 auto i = i0; 114 while (1) 115 { 116 auto j1 = 2 * i + 1; 117 if (j1 >= n || j1 < 0) 118 { // j1 < 0 after int overflow 119 break; 120 } 121 auto j = j1; // left child 122 auto j2 = j1 + 1; 123 if (j2 < n && _queue.Less(j2, j1)) 124 { 125 j = j2; // = 2*i + 2 // right child 126 } 127 if (!_queue.Less(j, i)) 128 { 129 break; 130 } 131 _queue.Swap(i, j); 132 i = j; 133 } 134 return i > i0; 135 } 136 137 } 138 139 unittest 140 { 141 import neton.lease.Heap; 142 import neton.lease.LeaseQueue; 143 144 Heap!LeaseQueue queue; 145 for (int i = 0; i < 10; i++) 146 { 147 LeaseWithTime item = {id: 148 i, time : 10 - i}; 149 queue.Push(item); 150 } 151 152 Heap!LeaseQueue queue2 = queue; 153 LeaseWithTime item = {id: 154 12, time : 4}; 155 queue2.Push(item); 156 while (queue2.lenght != 0) 157 { 158 writeln(" pop : ", queue2.Pop!LeaseWithTime()); 159 } 160 }