1 /* Priority queue functions.
2 Copyright (C) 2003 Yasuhiro Ohara
4 This file is part of GNU Zebra.
6 GNU Zebra is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2, or (at your
9 option) any later version.
11 GNU Zebra is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Zebra; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
26 /* priority queue using heap sort */
28 /* pqueue->cmp() controls the order of sorting (i.e, ascending or
29 descending). If you want the left node to move upper of the heap
30 binary tree, make cmp() to return less than 0. for example, if cmp
31 (10, 20) returns -1, the sorting is ascending order. if cmp (10,
32 20) returns 1, the sorting is descending order. if cmp (10, 20)
33 returns 0, this library does not do sorting (which will not be what
34 you want). To be brief, if the contents of cmp_func (left, right)
35 is left - right, dequeue () returns the smallest node. Otherwise
36 (if the contents is right - left), dequeue () returns the largest
39 #define DATA_SIZE (sizeof (void *))
40 #define PARENT_OF(x) ((x - 1) / 2)
41 #define LEFT_OF(x) (2 * x + 1)
42 #define RIGHT_OF(x) (2 * x + 2)
43 #define HAVE_CHILD(x,q) (x < (q)->size / 2)
46 trickle_up (int index
, struct pqueue
*queue
)
50 /* Save current node as tmp node. */
51 tmp
= queue
->array
[index
];
53 /* Continue until the node reaches top or the place where the parent
54 node should be upper than the tmp node. */
56 (*queue
->cmp
) (tmp
, queue
->array
[PARENT_OF (index
)]) < 0)
58 /* actually trickle up */
59 queue
->array
[index
] = queue
->array
[PARENT_OF (index
)];
60 if (queue
->update
!= NULL
)
61 (*queue
->update
) (queue
->array
[index
], index
);
62 index
= PARENT_OF (index
);
65 /* Restore the tmp node to appropriate place. */
66 queue
->array
[index
] = tmp
;
67 if (queue
->update
!= NULL
)
68 (*queue
->update
) (tmp
, index
);
72 trickle_down (int index
, struct pqueue
*queue
)
77 /* Save current node as tmp node. */
78 tmp
= queue
->array
[index
];
80 /* Continue until the node have at least one (left) child. */
81 while (HAVE_CHILD (index
, queue
))
83 /* If right child exists, and if the right child is more proper
85 if (RIGHT_OF (index
) < queue
->size
&&
86 (*queue
->cmp
) (queue
->array
[LEFT_OF (index
)],
87 queue
->array
[RIGHT_OF (index
)]) > 0)
88 which
= RIGHT_OF (index
);
90 which
= LEFT_OF (index
);
92 /* If the tmp node should be upper than the child, break. */
93 if ((*queue
->cmp
) (queue
->array
[which
], tmp
) > 0)
96 /* Actually trickle down the tmp node. */
97 queue
->array
[index
] = queue
->array
[which
];
98 if (queue
->update
!= NULL
)
99 (*queue
->update
) (queue
->array
[index
], index
);
103 /* Restore the tmp node to appropriate place. */
104 queue
->array
[index
] = tmp
;
105 if (queue
->update
!= NULL
)
106 (*queue
->update
) (tmp
, index
);
112 struct pqueue
*queue
;
114 queue
= XCALLOC (MTYPE_PQUEUE
, sizeof (struct pqueue
));
116 queue
->array
= XCALLOC (MTYPE_PQUEUE_DATA
,
117 DATA_SIZE
* PQUEUE_INIT_ARRAYSIZE
);
118 queue
->array_size
= PQUEUE_INIT_ARRAYSIZE
;
120 /* By default we want nothing to happen when a node changes. */
121 queue
->update
= NULL
;
126 pqueue_delete (struct pqueue
*queue
)
128 XFREE (MTYPE_PQUEUE_DATA
, queue
->array
);
129 XFREE (MTYPE_PQUEUE
, queue
);
133 pqueue_expand (struct pqueue
*queue
)
137 newarray
= XCALLOC (MTYPE_PQUEUE_DATA
, queue
->array_size
* DATA_SIZE
* 2);
138 if (newarray
== NULL
)
141 memcpy (newarray
, queue
->array
, queue
->array_size
* DATA_SIZE
);
143 XFREE (MTYPE_PQUEUE_DATA
, queue
->array
);
144 queue
->array
= newarray
;
145 queue
->array_size
*= 2;
151 pqueue_enqueue (void *data
, struct pqueue
*queue
)
153 if (queue
->size
+ 2 >= queue
->array_size
&& ! pqueue_expand (queue
))
156 queue
->array
[queue
->size
] = data
;
157 if (queue
->update
!= NULL
)
158 (*queue
->update
) (data
, queue
->size
);
159 trickle_up (queue
->size
, queue
);
164 pqueue_dequeue (struct pqueue
*queue
)
166 void *data
= queue
->array
[0];
167 queue
->array
[0] = queue
->array
[--queue
->size
];
168 trickle_down (0, queue
);