• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * A Pairing Heap implementation.
3  *
4  * "The Pairing Heap: A New Form of Self-Adjusting Heap"
5  * https://www.cs.cmu.edu/~sleator/papers/pairing-heaps.pdf
6  *
7  * With auxiliary twopass list, described in a follow on paper.
8  *
9  * "Pairing Heaps: Experiments and Analysis"
10  * http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.106.2988&rep=rep1&type=pdf
11  *
12  *******************************************************************************
13  */
14 
15 #ifndef PH_H_
16 #define	PH_H_
17 
18 /* Node structure. */
19 #define	phn(a_type)							\
20 struct {								\
21 	a_type	*phn_prev;						\
22 	a_type	*phn_next;						\
23 	a_type	*phn_lchild;						\
24 }
25 
26 /* Root structure. */
27 #define	ph(a_type)							\
28 struct {								\
29 	a_type	*ph_root;						\
30 }
31 
32 /* Internal utility macros. */
33 #define	phn_lchild_get(a_type, a_field, a_phn)				\
34 	(a_phn->a_field.phn_lchild)
35 #define	phn_lchild_set(a_type, a_field, a_phn, a_lchild) do {		\
36 	a_phn->a_field.phn_lchild = a_lchild;				\
37 } while (0)
38 
39 #define	phn_next_get(a_type, a_field, a_phn)				\
40 	(a_phn->a_field.phn_next)
41 #define	phn_prev_set(a_type, a_field, a_phn, a_prev) do {		\
42 	a_phn->a_field.phn_prev = a_prev;				\
43 } while (0)
44 
45 #define	phn_prev_get(a_type, a_field, a_phn)				\
46 	(a_phn->a_field.phn_prev)
47 #define	phn_next_set(a_type, a_field, a_phn, a_next) do {		\
48 	a_phn->a_field.phn_next = a_next;				\
49 } while (0)
50 
51 #define	phn_merge_ordered(a_type, a_field, a_phn0, a_phn1, a_cmp) do {	\
52 	a_type *phn0child;						\
53 									\
54 	assert(a_phn0 != NULL);						\
55 	assert(a_phn1 != NULL);						\
56 	assert(a_cmp(a_phn0, a_phn1) <= 0);				\
57 									\
58 	phn_prev_set(a_type, a_field, a_phn1, a_phn0);			\
59 	phn0child = phn_lchild_get(a_type, a_field, a_phn0);		\
60 	phn_next_set(a_type, a_field, a_phn1, phn0child);		\
61 	if (phn0child != NULL)						\
62 		phn_prev_set(a_type, a_field, phn0child, a_phn1);	\
63 	phn_lchild_set(a_type, a_field, a_phn0, a_phn1);		\
64 } while (0)
65 
66 #define	phn_merge(a_type, a_field, a_phn0, a_phn1, a_cmp, r_phn) do {	\
67 	if (a_phn0 == NULL)						\
68 		r_phn = a_phn1;						\
69 	else if (a_phn1 == NULL)					\
70 		r_phn = a_phn0;						\
71 	else if (a_cmp(a_phn0, a_phn1) < 0) {				\
72 		phn_merge_ordered(a_type, a_field, a_phn0, a_phn1,	\
73 		    a_cmp);						\
74 		r_phn = a_phn0;						\
75 	} else {							\
76 		phn_merge_ordered(a_type, a_field, a_phn1, a_phn0,	\
77 		    a_cmp);						\
78 		r_phn = a_phn1;						\
79 	}								\
80 } while (0)
81 
82 #define	ph_merge_siblings(a_type, a_field, a_phn, a_cmp, r_phn) do {	\
83 	a_type *head = NULL;						\
84 	a_type *tail = NULL;						\
85 	a_type *phn0 = a_phn;						\
86 	a_type *phn1 = phn_next_get(a_type, a_field, phn0);		\
87 									\
88 	/*								\
89 	 * Multipass merge, wherein the first two elements of a FIFO	\
90 	 * are repeatedly merged, and each result is appended to the	\
91 	 * singly linked FIFO, until the FIFO contains only a single	\
92 	 * element.  We start with a sibling list but no reference to	\
93 	 * its tail, so we do a single pass over the sibling list to	\
94 	 * populate the FIFO.						\
95 	 */								\
96 	if (phn1 != NULL) {						\
97 		a_type *phnrest = phn_next_get(a_type, a_field, phn1);	\
98 		if (phnrest != NULL)					\
99 			phn_prev_set(a_type, a_field, phnrest, NULL);	\
100 		phn_prev_set(a_type, a_field, phn0, NULL);		\
101 		phn_next_set(a_type, a_field, phn0, NULL);		\
102 		phn_prev_set(a_type, a_field, phn1, NULL);		\
103 		phn_next_set(a_type, a_field, phn1, NULL);		\
104 		phn_merge(a_type, a_field, phn0, phn1, a_cmp, phn0);	\
105 		head = tail = phn0;					\
106 		phn0 = phnrest;						\
107 		while (phn0 != NULL) {					\
108 			phn1 = phn_next_get(a_type, a_field, phn0);	\
109 			if (phn1 != NULL) {				\
110 				phnrest = phn_next_get(a_type, a_field,	\
111 				    phn1);				\
112 				if (phnrest != NULL) {			\
113 					phn_prev_set(a_type, a_field,	\
114 					    phnrest, NULL);		\
115 				}					\
116 				phn_prev_set(a_type, a_field, phn0,	\
117 				    NULL);				\
118 				phn_next_set(a_type, a_field, phn0,	\
119 				    NULL);				\
120 				phn_prev_set(a_type, a_field, phn1,	\
121 				    NULL);				\
122 				phn_next_set(a_type, a_field, phn1,	\
123 				    NULL);				\
124 				phn_merge(a_type, a_field, phn0, phn1,	\
125 				    a_cmp, phn0);			\
126 				phn_next_set(a_type, a_field, tail,	\
127 				    phn0);				\
128 				tail = phn0;				\
129 				phn0 = phnrest;				\
130 			} else {					\
131 				phn_next_set(a_type, a_field, tail,	\
132 				    phn0);				\
133 				tail = phn0;				\
134 				phn0 = NULL;				\
135 			}						\
136 		}							\
137 		phn0 = head;						\
138 		phn1 = phn_next_get(a_type, a_field, phn0);		\
139 		if (phn1 != NULL) {					\
140 			while (true) {					\
141 				head = phn_next_get(a_type, a_field,	\
142 				    phn1);				\
143 				assert(phn_prev_get(a_type, a_field,	\
144 				    phn0) == NULL);			\
145 				phn_next_set(a_type, a_field, phn0,	\
146 				    NULL);				\
147 				assert(phn_prev_get(a_type, a_field,	\
148 				    phn1) == NULL);			\
149 				phn_next_set(a_type, a_field, phn1,	\
150 				    NULL);				\
151 				phn_merge(a_type, a_field, phn0, phn1,	\
152 				    a_cmp, phn0);			\
153 				if (head == NULL)			\
154 					break;				\
155 				phn_next_set(a_type, a_field, tail,	\
156 				    phn0);				\
157 				tail = phn0;				\
158 				phn0 = head;				\
159 				phn1 = phn_next_get(a_type, a_field,	\
160 				    phn0);				\
161 			}						\
162 		}							\
163 	}								\
164 	r_phn = phn0;							\
165 } while (0)
166 
167 #define	ph_merge_aux(a_type, a_field, a_ph, a_cmp) do {			\
168 	a_type *phn = phn_next_get(a_type, a_field, a_ph->ph_root);	\
169 	if (phn != NULL) {						\
170 		phn_prev_set(a_type, a_field, a_ph->ph_root, NULL);	\
171 		phn_next_set(a_type, a_field, a_ph->ph_root, NULL);	\
172 		phn_prev_set(a_type, a_field, phn, NULL);		\
173 		ph_merge_siblings(a_type, a_field, phn, a_cmp, phn);	\
174 		assert(phn_next_get(a_type, a_field, phn) == NULL);	\
175 		phn_merge(a_type, a_field, a_ph->ph_root, phn, a_cmp,	\
176 		    a_ph->ph_root);					\
177 	}								\
178 } while (0)
179 
180 #define	ph_merge_children(a_type, a_field, a_phn, a_cmp, r_phn) do {	\
181 	a_type *lchild = phn_lchild_get(a_type, a_field, a_phn);	\
182 	if (lchild == NULL)						\
183 		r_phn = NULL;						\
184 	else {								\
185 		ph_merge_siblings(a_type, a_field, lchild, a_cmp,	\
186 		    r_phn);						\
187 	}								\
188 } while (0)
189 
190 /*
191  * The ph_proto() macro generates function prototypes that correspond to the
192  * functions generated by an equivalently parameterized call to ph_gen().
193  */
194 #define	ph_proto(a_attr, a_prefix, a_ph_type, a_type)			\
195 a_attr void	a_prefix##new(a_ph_type *ph);				\
196 a_attr bool	a_prefix##empty(a_ph_type *ph);				\
197 a_attr a_type	*a_prefix##first(a_ph_type *ph);			\
198 a_attr void	a_prefix##insert(a_ph_type *ph, a_type *phn);		\
199 a_attr a_type	*a_prefix##remove_first(a_ph_type *ph);			\
200 a_attr void	a_prefix##remove(a_ph_type *ph, a_type *phn);
201 
202 /*
203  * The ph_gen() macro generates a type-specific pairing heap implementation,
204  * based on the above cpp macros.
205  */
206 #define	ph_gen(a_attr, a_prefix, a_ph_type, a_type, a_field, a_cmp)	\
207 a_attr void								\
208 a_prefix##new(a_ph_type *ph)						\
209 {									\
210 									\
211 	memset(ph, 0, sizeof(ph(a_type)));				\
212 }									\
213 a_attr bool								\
214 a_prefix##empty(a_ph_type *ph)						\
215 {									\
216 									\
217 	return (ph->ph_root == NULL);					\
218 }									\
219 a_attr a_type *								\
220 a_prefix##first(a_ph_type *ph)						\
221 {									\
222 									\
223 	if (ph->ph_root == NULL)					\
224 		return (NULL);						\
225 	ph_merge_aux(a_type, a_field, ph, a_cmp);			\
226 	return (ph->ph_root);						\
227 }									\
228 a_attr void								\
229 a_prefix##insert(a_ph_type *ph, a_type *phn)				\
230 {									\
231 									\
232 	memset(&phn->a_field, 0, sizeof(phn(a_type)));			\
233 									\
234 	/*								\
235 	 * Treat the root as an aux list during insertion, and lazily	\
236 	 * merge during a_prefix##remove_first().  For elements that	\
237 	 * are inserted, then removed via a_prefix##remove() before the	\
238 	 * aux list is ever processed, this makes insert/remove		\
239 	 * constant-time, whereas eager merging would make insert	\
240 	 * O(log n).							\
241 	 */								\
242 	if (ph->ph_root == NULL)					\
243 		ph->ph_root = phn;					\
244 	else {								\
245 		phn_next_set(a_type, a_field, phn, phn_next_get(a_type,	\
246 		    a_field, ph->ph_root));				\
247 		if (phn_next_get(a_type, a_field, ph->ph_root) !=	\
248 		    NULL) {						\
249 			phn_prev_set(a_type, a_field,			\
250 			    phn_next_get(a_type, a_field, ph->ph_root),	\
251 			    phn);					\
252 		}							\
253 		phn_prev_set(a_type, a_field, phn, ph->ph_root);	\
254 		phn_next_set(a_type, a_field, ph->ph_root, phn);	\
255 	}								\
256 }									\
257 a_attr a_type *								\
258 a_prefix##remove_first(a_ph_type *ph)					\
259 {									\
260 	a_type *ret;							\
261 									\
262 	if (ph->ph_root == NULL)					\
263 		return (NULL);						\
264 	ph_merge_aux(a_type, a_field, ph, a_cmp);			\
265 									\
266 	ret = ph->ph_root;						\
267 									\
268 	ph_merge_children(a_type, a_field, ph->ph_root, a_cmp,		\
269 	    ph->ph_root);						\
270 									\
271 	return (ret);							\
272 }									\
273 a_attr void								\
274 a_prefix##remove(a_ph_type *ph, a_type *phn)				\
275 {									\
276 	a_type *replace, *parent;					\
277 									\
278 	/*								\
279 	 * We can delete from aux list without merging it, but we need	\
280 	 * to merge if we are dealing with the root node.		\
281 	 */								\
282 	if (ph->ph_root == phn) {					\
283 		ph_merge_aux(a_type, a_field, ph, a_cmp);		\
284 		if (ph->ph_root == phn) {				\
285 			ph_merge_children(a_type, a_field, ph->ph_root,	\
286 			    a_cmp, ph->ph_root);			\
287 			return;						\
288 		}							\
289 	}								\
290 									\
291 	/* Get parent (if phn is leftmost child) before mutating. */	\
292 	if ((parent = phn_prev_get(a_type, a_field, phn)) != NULL) {	\
293 		if (phn_lchild_get(a_type, a_field, parent) != phn)	\
294 			parent = NULL;					\
295 	}								\
296 	/* Find a possible replacement node, and link to parent. */	\
297 	ph_merge_children(a_type, a_field, phn, a_cmp, replace);	\
298 	/* Set next/prev for sibling linked list. */			\
299 	if (replace != NULL) {						\
300 		if (parent != NULL) {					\
301 			phn_prev_set(a_type, a_field, replace, parent);	\
302 			phn_lchild_set(a_type, a_field, parent,		\
303 			    replace);					\
304 		} else {						\
305 			phn_prev_set(a_type, a_field, replace,		\
306 			    phn_prev_get(a_type, a_field, phn));	\
307 			if (phn_prev_get(a_type, a_field, phn) !=	\
308 			    NULL) {					\
309 				phn_next_set(a_type, a_field,		\
310 				    phn_prev_get(a_type, a_field, phn),	\
311 				    replace);				\
312 			}						\
313 		}							\
314 		phn_next_set(a_type, a_field, replace,			\
315 		    phn_next_get(a_type, a_field, phn));		\
316 		if (phn_next_get(a_type, a_field, phn) != NULL) {	\
317 			phn_prev_set(a_type, a_field,			\
318 			    phn_next_get(a_type, a_field, phn),		\
319 			    replace);					\
320 		}							\
321 	} else {							\
322 		if (parent != NULL) {					\
323 			a_type *next = phn_next_get(a_type, a_field,	\
324 			    phn);					\
325 			phn_lchild_set(a_type, a_field, parent, next);	\
326 			if (next != NULL) {				\
327 				phn_prev_set(a_type, a_field, next,	\
328 				    parent);				\
329 			}						\
330 		} else {						\
331 			assert(phn_prev_get(a_type, a_field, phn) !=	\
332 			    NULL);					\
333 			phn_next_set(a_type, a_field,			\
334 			    phn_prev_get(a_type, a_field, phn),		\
335 			    phn_next_get(a_type, a_field, phn));	\
336 		}							\
337 		if (phn_next_get(a_type, a_field, phn) != NULL) {	\
338 			phn_prev_set(a_type, a_field,			\
339 			    phn_next_get(a_type, a_field, phn),		\
340 			    phn_prev_get(a_type, a_field, phn));	\
341 		}							\
342 	}								\
343 }
344 
345 #endif /* PH_H_ */
346