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 }