| 1 | /* $Id$ $Revision$ */ |
| 2 | /* vim:set shiftwidth=4 ts=8: */ |
| 3 | |
| 4 | /************************************************************************* |
| 5 | * Copyright (c) 2011 AT&T Intellectual Property |
| 6 | * All rights reserved. This program and the accompanying materials |
| 7 | * are made available under the terms of the Eclipse Public License v1.0 |
| 8 | * which accompanies this distribution, and is available at |
| 9 | * http://www.eclipse.org/legal/epl-v10.html |
| 10 | * |
| 11 | * Contributors: See CVS logs. Details at http://www.graphviz.org/ |
| 12 | *************************************************************************/ |
| 13 | |
| 14 | #include "LinkedList.h" |
| 15 | #include "PriorityQueue.h" |
| 16 | #include "memory.h" |
| 17 | #include "logic.h" |
| 18 | #include "assert.h" |
| 19 | #include "arith.h" |
| 20 | |
| 21 | #define MALLOC gmalloc |
| 22 | #define REALLOC grealloc |
| 23 | #define FREE free |
| 24 | #define MEMCPY memcpy |
| 25 | |
| 26 | |
| 27 | PriorityQueue PriorityQueue_new(int n, int ngain){ |
| 28 | PriorityQueue q; |
| 29 | int i; |
| 30 | q = N_GNEW(1,struct PriorityQueue_struct); |
| 31 | q->count = 0; |
| 32 | q->n = n; |
| 33 | q->ngain = ngain; |
| 34 | q->gain_max = -1;/* no entries yet */ |
| 35 | q->buckets = N_GNEW((ngain+1),DoubleLinkedList); |
| 36 | for (i = 0; i < ngain+1; i++) (q->buckets)[i] = NULL; |
| 37 | |
| 38 | q->where = N_GNEW((n+1),DoubleLinkedList); |
| 39 | for (i = 0; i < n+1; i++) (q->where)[i] = NULL; |
| 40 | |
| 41 | q->gain = N_GNEW((n+1),int); |
| 42 | for (i = 0; i < n+1; i++) (q->gain)[i] = -999; |
| 43 | return q; |
| 44 | |
| 45 | } |
| 46 | |
| 47 | void PriorityQueue_delete(PriorityQueue q){ |
| 48 | int i; |
| 49 | |
| 50 | if (q){ |
| 51 | if (q->buckets){ |
| 52 | for (i = 0; i < q->ngain+1; i++) DoubleLinkedList_delete((q->buckets)[i], free); |
| 53 | FREE(q->buckets); |
| 54 | } |
| 55 | |
| 56 | if (q->where){ |
| 57 | FREE(q->where); |
| 58 | } |
| 59 | |
| 60 | FREE(q->gain); |
| 61 | FREE(q); |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | PriorityQueue PriorityQueue_push(PriorityQueue q, int i, int gain){ |
| 66 | DoubleLinkedList l; |
| 67 | int *data, gainold; |
| 68 | |
| 69 | assert(q); |
| 70 | assert(gain <= q->ngain); |
| 71 | |
| 72 | |
| 73 | if (!(q->where)[i]){ |
| 74 | /* this entry is no in the queue yet, so this is a new addition */ |
| 75 | |
| 76 | (q->count)++; |
| 77 | if (gain > q->gain_max) q->gain_max = gain; |
| 78 | q->gain[i] = gain; |
| 79 | |
| 80 | data = N_GNEW(1,int); |
| 81 | data[0] = i; |
| 82 | if ((l = (q->buckets)[gain])){ |
| 83 | (q->buckets)[gain] = (q->where)[i] = DoubleLinkedList_prepend(l, data); |
| 84 | } else { |
| 85 | (q->buckets)[gain] = (q->where)[i] = DoubleLinkedList_new(data); |
| 86 | } |
| 87 | |
| 88 | } else { |
| 89 | /* update gain for an exisiting entry */ |
| 90 | l = q->where[i]; |
| 91 | gainold = q->gain[i]; |
| 92 | q->where[i] = NULL; |
| 93 | (q->count)--; |
| 94 | DoubleLinkedList_delete_element(l, free, &((q->buckets)[gainold])); |
| 95 | return PriorityQueue_push(q, i, gain); |
| 96 | } |
| 97 | return q; |
| 98 | } |
| 99 | |
| 100 | int PriorityQueue_pop(PriorityQueue q, int *i, int *gain){ |
| 101 | int gain_max; |
| 102 | DoubleLinkedList l; |
| 103 | int *data; |
| 104 | |
| 105 | if (!q || q->count <= 0) return 0; |
| 106 | *gain = gain_max = q->gain_max; |
| 107 | (q->count)--; |
| 108 | l = (q->buckets)[gain_max]; |
| 109 | data = (int*) DoubleLinkedList_get_data(l); |
| 110 | *i = data[0]; |
| 111 | |
| 112 | DoubleLinkedList_delete_element(l, free, &((q->buckets)[gain_max])); |
| 113 | if (!(q->buckets)[gain_max]){/* the bin that contain the best gain is empty now after poping */ |
| 114 | while (gain_max >= 0 && !(q->buckets)[gain_max]) gain_max--; |
| 115 | q->gain_max = gain_max; |
| 116 | } |
| 117 | q->where[*i] = NULL; |
| 118 | q->gain[*i] = -999; |
| 119 | return 1; |
| 120 | } |
| 121 | |
| 122 | |
| 123 | |
| 124 | |
| 125 | int PriorityQueue_get_gain(PriorityQueue q, int i){ |
| 126 | return q->gain[i]; |
| 127 | } |
| 128 | |
| 129 | int PriorityQueue_remove(PriorityQueue q, int i){ |
| 130 | /* remove an entry from the queue. If error, return 0. */ |
| 131 | int gain, gain_max; |
| 132 | DoubleLinkedList l; |
| 133 | |
| 134 | if (!q || q->count <= 0) return 0; |
| 135 | gain = q->gain[i]; |
| 136 | (q->count)--; |
| 137 | l = (q->where)[i]; |
| 138 | |
| 139 | DoubleLinkedList_delete_element(l, free, &((q->buckets)[gain])); |
| 140 | |
| 141 | if (gain == (gain_max = q->gain_max) && !(q->buckets)[gain_max]){/* the bin that contain the best gain is empty now after poping */ |
| 142 | while (gain_max >= 0 && !(q->buckets)[gain_max]) gain_max--; |
| 143 | q->gain_max = gain_max; |
| 144 | } |
| 145 | q->where[i] = NULL; |
| 146 | q->gain[i] = -999; |
| 147 | return 1; |
| 148 | } |
| 149 | |
| 150 | /* |
| 151 | |
| 152 | main(){ |
| 153 | int i, gain; |
| 154 | |
| 155 | |
| 156 | PriorityQueue q; |
| 157 | q = PriorityQueue_new(10,100); |
| 158 | PriorityQueue_push(q, 3, 1); |
| 159 | PriorityQueue_push(q, 2, 2); |
| 160 | PriorityQueue_push(q, 4, 2); |
| 161 | PriorityQueue_push(q, 5, 2); |
| 162 | PriorityQueue_push(q, 1, 100); |
| 163 | PriorityQueue_push(q, 2, 1); |
| 164 | while (PriorityQueue_pop(q, &i, &gain)){ |
| 165 | printf("i = %d gain = %d\n", i, gain); |
| 166 | } |
| 167 | |
| 168 | printf("=========\n"); |
| 169 | PriorityQueue_push(q, 3, 1); |
| 170 | PriorityQueue_push(q, 2, 2); |
| 171 | PriorityQueue_push(q, 4, 2); |
| 172 | PriorityQueue_push(q, 5, 2); |
| 173 | PriorityQueue_push(q, 1, 100); |
| 174 | PriorityQueue_push(q, 2, 1); |
| 175 | PriorityQueue_push(q, 2, 100); |
| 176 | while (PriorityQueue_pop(q, &i, &gain)){ |
| 177 | printf("i = %d gain = %d\n", i, gain); |
| 178 | } |
| 179 | |
| 180 | |
| 181 | printf("====after removing 3 and 2 =====\n"); |
| 182 | PriorityQueue_push(q, 3, 1); |
| 183 | PriorityQueue_push(q, 2, 2); |
| 184 | PriorityQueue_push(q, 4, 2); |
| 185 | PriorityQueue_push(q, 5, 2); |
| 186 | PriorityQueue_push(q, 1, 100); |
| 187 | PriorityQueue_push(q, 2, 1); |
| 188 | PriorityQueue_push(q, 2, 100); |
| 189 | PriorityQueue_remove(q, 3); |
| 190 | PriorityQueue_remove(q, 2); |
| 191 | while (PriorityQueue_pop(q, &i, &gain)){ |
| 192 | printf("i = %d gain = %d\n", i, gain); |
| 193 | } |
| 194 | PriorityQueue_delete(q); |
| 195 | |
| 196 | } |
| 197 | |
| 198 | */ |
| 199 | |