|
1 /* |
|
2 * Copyright 2007 Baylor University |
|
3 * |
|
4 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 * you may not use this file except in compliance with the License. |
|
6 * You may obtain a copy of the License at |
|
7 * |
|
8 * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 * |
|
10 * Unless required by applicable law or agreed to in writing, software |
|
11 * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 * See the License for the specific language governing permissions and |
|
14 * limitations under the License. |
|
15 */ |
|
16 |
|
17 #ifndef _PROPHET_UTIL_H_ |
|
18 #define _PROPHET_UTIL_H_ |
|
19 |
|
20 #include <string> |
|
21 #include <algorithm> |
|
22 #include <vector> |
|
23 |
|
24 namespace prophet |
|
25 { |
|
26 |
|
27 #define FOUR_BYTE_ALIGN(x) (((x) % 4) != 0) ? ((x) + (4 - ((x) % 4))) : (x) |
|
28 |
|
29 struct less_string : public std::less<std::string> |
|
30 { |
|
31 bool operator() (const std::string& a, const std::string& b) const |
|
32 { |
|
33 return (a.compare(b) < 0); |
|
34 } |
|
35 }; |
|
36 |
|
37 template<typename T,typename size_type=size_t> |
|
38 struct DoNothing |
|
39 { |
|
40 inline void operator()(T& t, size_type pos) |
|
41 { |
|
42 (void)t; |
|
43 (void)pos; |
|
44 } |
|
45 }; |
|
46 |
|
47 #define PARENT(_x) (((_x) - 1) >> 1) |
|
48 #define LEFT(_x) (((_x) << 1) + 1) |
|
49 |
|
50 template <typename UnitType, |
|
51 typename Sequence=std::vector<UnitType>, |
|
52 typename Compare=std::less<typename Sequence::value_type>, |
|
53 typename UpdateElem=DoNothing<UnitType,typename Sequence::size_type> > |
|
54 class Heap |
|
55 { |
|
56 public: |
|
57 typedef typename Sequence::value_type value_type; |
|
58 typedef typename Sequence::size_type size_type; |
|
59 typedef typename Sequence::iterator iterator; |
|
60 typedef typename Sequence::const_reference const_reference; |
|
61 |
|
62 /** |
|
63 * Default constructor |
|
64 */ |
|
65 Heap() |
|
66 { |
|
67 comp_ = new Compare(); |
|
68 } |
|
69 |
|
70 /** |
|
71 * Heap assumes ownership of comp |
|
72 */ |
|
73 Heap(Compare* comp) |
|
74 : comp_(comp) |
|
75 { |
|
76 } |
|
77 |
|
78 /** |
|
79 * Destructor |
|
80 */ |
|
81 virtual ~Heap() { delete comp_; } |
|
82 |
|
83 /** |
|
84 * Constant reference to current compare |
|
85 */ |
|
86 inline |
|
87 const Compare* compare() const { return comp_; } |
|
88 |
|
89 /** |
|
90 * Change to new compare and reorder heap |
|
91 */ |
|
92 inline |
|
93 void set_compare(Compare* comp) { |
|
94 delete comp_; |
|
95 comp_ = comp; |
|
96 make_heap(0); |
|
97 update_elements(); |
|
98 } |
|
99 |
|
100 /** |
|
101 * Verify heap order |
|
102 */ |
|
103 inline |
|
104 static bool is_heap(const Sequence& list, Compare& comp) { |
|
105 size_type len = list.size(); |
|
106 size_type parent = 0; |
|
107 for (size_type child = 1; child < len; child++) { |
|
108 if ((comp)(list[parent],list[child])) |
|
109 return false; |
|
110 if ((child & 1) == 0) |
|
111 parent++; |
|
112 } |
|
113 return true; |
|
114 } |
|
115 |
|
116 /** |
|
117 * Pass over entire sequence to ensure each element's heap pointer |
|
118 */ |
|
119 inline |
|
120 void update_elements() { |
|
121 size_type pos = size(); |
|
122 while (pos-- > 0) |
|
123 (upd_)(seq_[pos],pos); |
|
124 } |
|
125 |
|
126 /** |
|
127 * Return true if underlying sequence is empty |
|
128 */ |
|
129 bool empty() const { return seq_.empty(); } |
|
130 |
|
131 /** |
|
132 * Return number of elements in underlying sequence |
|
133 */ |
|
134 size_type size() const { return seq_.size(); } |
|
135 |
|
136 /** |
|
137 * Return read-only reference to top of heap |
|
138 */ |
|
139 const_reference top() const { return seq_.front(); } |
|
140 |
|
141 /** |
|
142 * Add data to heap, return index of insertion point |
|
143 */ |
|
144 inline |
|
145 void add(value_type x) { |
|
146 // first add value to end of underlying sequence |
|
147 seq_.push_back(x); |
|
148 // re-order sequence into heap |
|
149 size_type pos = heap_up(size() - 1); |
|
150 // update element with new heap position |
|
151 (upd_)(seq_[pos],pos); |
|
152 } |
|
153 |
|
154 /** |
|
155 * Remove element from heap by position, re-heap remaining |
|
156 * elements |
|
157 */ |
|
158 inline |
|
159 void remove(size_t pos) { |
|
160 // overwrite victim with last element |
|
161 seq_[pos] = seq_[size()-1]; |
|
162 (upd_)(seq_[pos],pos); |
|
163 // remove last element |
|
164 seq_.pop_back(); |
|
165 // reheap everything down from pos |
|
166 heap_down(pos); |
|
167 } |
|
168 |
|
169 /** |
|
170 * Constant reference to underlying sequence |
|
171 */ |
|
172 const Sequence& sequence() const { return seq_; } |
|
173 |
|
174 protected: |
|
175 /** |
|
176 * Assuming left and right subtrees are in heap order, push hole |
|
177 * down the tree until it reaches heap order |
|
178 */ |
|
179 inline |
|
180 size_type heap_down(size_type hole) { |
|
181 |
|
182 size_type top = hole; |
|
183 size_type left = LEFT(top); |
|
184 size_type right = left + 1; |
|
185 |
|
186 while (left < size()) { |
|
187 |
|
188 if ((*comp_)(seq_[hole],seq_[left])) |
|
189 top = left; |
|
190 |
|
191 if (right < size() && (*comp_)(seq_[top],seq_[right])) |
|
192 top = right; |
|
193 |
|
194 // heap order throughout, we're done |
|
195 if (top == hole) |
|
196 break; |
|
197 |
|
198 // swap top and hole |
|
199 swap(top,hole); |
|
200 |
|
201 // reset values for next iteration |
|
202 hole = top; |
|
203 left = LEFT(top); |
|
204 right = left + 1; |
|
205 } |
|
206 return top; |
|
207 } |
|
208 |
|
209 /** |
|
210 * Assuming tree is heap order above last, bubble up last until |
|
211 * the tree is in heap order |
|
212 */ |
|
213 inline |
|
214 size_type heap_up(size_type last) { |
|
215 |
|
216 size_type parent = PARENT(last); |
|
217 |
|
218 while (last > 0) { |
|
219 |
|
220 // check for heap order |
|
221 if (!(*comp_)(seq_[parent],seq_[last])) |
|
222 break; |
|
223 |
|
224 swap(parent,last); |
|
225 |
|
226 last = parent; |
|
227 parent = PARENT(last); |
|
228 } |
|
229 return last; |
|
230 } |
|
231 |
|
232 /** |
|
233 * Begin with last node (a leaf, therefore a subtree of size 1, |
|
234 * therefore a heap) and work upwards to build heap |
|
235 */ |
|
236 inline |
|
237 void make_heap(size_type first) { |
|
238 |
|
239 // first scan down to a leaf node from first |
|
240 size_type left = LEFT(first); |
|
241 while (left < size() - 1) |
|
242 left = LEFT(left); |
|
243 |
|
244 // now work back up towards first |
|
245 size_type parent = PARENT(left); |
|
246 while (true) { |
|
247 heap_down(parent); |
|
248 if (parent == first) break; |
|
249 parent--; |
|
250 } |
|
251 } |
|
252 |
|
253 /** |
|
254 * Swap function used by heap_up, heap_down |
|
255 */ |
|
256 inline |
|
257 void swap(size_type a, size_type b) { |
|
258 std::iter_swap<iterator>( |
|
259 seq_.begin() + a, |
|
260 seq_.begin() + b); |
|
261 (upd_)(seq_[a],a); |
|
262 (upd_)(seq_[b],b); |
|
263 } |
|
264 |
|
265 Sequence seq_; |
|
266 Compare* comp_; |
|
267 UpdateElem upd_; |
|
268 }; //template<> class Heap |
|
269 |
|
270 }; //namespace prophet |
|
271 |
|
272 #endif // _PROPHET_UTIL_H_ |