From: Martin Mares Date: Sun, 21 Oct 2012 15:10:20 +0000 (+0200) Subject: Heap: Interface cleanup X-Git-Tag: v5.99~106 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=f17e4350dcf0c033891e52b30b0c32a4a4fed5e0;p=libucw.git Heap: Interface cleanup The previous interfaces was mixing macros, which really perform the operation, with those where the caller performs the operation and the macro fixes the heap. This has for example lead to non-systematic side effects on the `num' variable. The change is backwards incompatible, all old code should hopefully fail to compile now. --- diff --git a/ucw/doc/heap.txt b/ucw/doc/heap.txt index 64729a17..605c696d 100644 --- a/ucw/doc/heap.txt +++ b/ucw/doc/heap.txt @@ -19,22 +19,18 @@ Example #define MY_CMP(x, y) ((x) < (y)) // Insert 20, 10, 30 - heap[n + 1] = 20; - HEAP_INSERT(int, heap, n, MY_CMP, HEAP_SWAP); - heap[n + 1] = 10; - HEAP_INSERT(int, heap, n, MY_CMP, HEAP_SWAP); - heap[n + 1] = 30; - HEAP_INSERT(int, heap, n, MY_CMP, HEAP_SWAP); + HEAP_INSERT(int, heap, n, MY_CMP, HEAP_SWAP, 20); + HEAP_INSERT(int, heap, n, MY_CMP, HEAP_SWAP, 10); + HEAP_INSERT(int, heap, n, MY_CMP, HEAP_SWAP, 30); // Remove the minimum (10) - HEAP_DELMIN(int, heap, n, MY_CMP, HEAP_SWAP); + HEAP_DELETE_MIN(int, heap, n, MY_CMP, HEAP_SWAP); // Print the new minimum (20) printf("%d", heap[1]); - // Increase the minimum by 20 to 40 - heap[1] += 20; - HEAP_INCREASE(int, heap, n, MY_CMP, HEAP_SWAP, 1); + // Increase the minimum to 40 + HEAP_INCREASE(int, heap, n, MY_CMP, HEAP_SWAP, 1, 40); // Print the new minimum (30) printf("%d", heap[1]); diff --git a/ucw/doc/relnotes.txt b/ucw/doc/relnotes.txt index a720fb59..74f4f781 100644 --- a/ucw/doc/relnotes.txt +++ b/ucw/doc/relnotes.txt @@ -5,6 +5,12 @@ WIP --- * The <> has been improved: +** *Incompatible:* The interface of the <> module was cleaned up + to remove non-systematic side-effects. The `HEAP_INSERT` operation is now + a proper insert (previously, it was just cleanup after insertion performed + by the caller), similarly `HEAP_INCREASE` and `HEAP_DECREASE`. The `HEAP_DELMIN` + operation was renamed to `HEAP_DELETE_MIN`. New operations `HEAP_REPLACE` and + `HEAP_REPLACE_MIN` have been added. ** Multiple instances of the configuration parser are supported. ** *Incompatible:* As there may be more instances, we can no longer use global variables to control the configuration system. In particular, diff --git a/ucw/heap.h b/ucw/heap.h index e0a33b02..ec8f4f3a 100644 --- a/ucw/heap.h +++ b/ucw/heap.h @@ -1,8 +1,8 @@ /* * UCW Library -- Universal Heap Macros * - * (c) 2001 Martin Mares - * (c) 2005 Tomas Valla + * (c) 2001--2012 Martin Mares + * (c) 2005--2012 Tomas Valla * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. @@ -41,7 +41,7 @@ * ------ ***/ -/* For internal usage. */ +/* For internal use. */ #define HEAP_BUBBLE_DOWN_J(heap,num,less,swap) \ for (;;) \ { \ @@ -56,7 +56,7 @@ _j = _l; \ } -/* For internal usage. */ +/* For internal use. */ #define HEAP_BUBBLE_UP_J(heap,num,less,swap) \ while (_j > 1) \ { \ @@ -68,7 +68,8 @@ } /** - * Shuffle the unordered array @heap of @num elements to become a valid heap. The time complexity is linear. + * Shuffle the items `heap[1]`, ..., `heap[num]` to get a valid heap. + * This operation takes linear time. **/ #define HEAP_INIT(type,heap,num,less,swap) \ do { \ @@ -84,10 +85,10 @@ } while(0) /** - * Delete the minimum element `heap[1]` in `O(log(n))` time. + * Delete the minimum element `heap[1]` in `O(log(n))` time. The @num variable is decremented. * The removed value is moved just after the resulting heap (`heap[num + 1]`). **/ -#define HEAP_DELMIN(type,heap,num,less,swap) \ +#define HEAP_DELETE_MIN(type,heap,num,less,swap) \ do { \ uns _j, _l; \ type x; \ @@ -98,56 +99,72 @@ } while(0) /** - * Insert `heap[num]` in `O(log(n))` time. The value of @num must be increased before. + * Insert a new element @elt to the heap. The @num variable is incremented. + * This operation takes `O(log(n))` time. **/ -#define HEAP_INSERT(type,heap,num,less,swap) \ +#define HEAP_INSERT(type,heap,num,less,swap,elt) \ do { \ uns _j, _u; \ type x; \ + heap[++num] = elt; \ _j = num; \ HEAP_BUBBLE_UP_J(heap,num,less,swap); \ } while(0) /** - * If you need to increase the value of `heap[pos]`, just do it and then call this macro to rebuild the heap. - * Only `heap[pos]` can be changed, the rest of the array must form a valid heap. + * Increase `heap[pos]` to a new value @elt (greater or equal to the previous value). * The time complexity is `O(log(n))`. **/ -#define HEAP_INCREASE(type,heap,num,less,swap,pos) \ +#define HEAP_INCREASE(type,heap,num,less,swap,pos,elt) \ do { \ uns _j, _l; \ type x; \ + heap[pos] = elt; \ _j = pos; \ HEAP_BUBBLE_DOWN_J(heap,num,less,swap); \ } while(0) /** - * If you need to decrease the value of `heap[pos]`, just do it and then call this macro to rebuild the heap. - * Only `heap[pos]` can be changed, the rest of the array must form a valid heap. + * Decrease `heap[pos]` to a new value @elt (less or equal to the previous value). * The time complexity is `O(log(n))`. **/ -#define HEAP_DECREASE(type,heap,num,less,swap,pos) \ +#define HEAP_DECREASE(type,heap,num,less,swap,pos,elt) \ do { \ uns _j, _u; \ type x; \ + heap[pos] = elt; \ _j = pos; \ HEAP_BUBBLE_UP_J(heap,num,less,swap); \ } while(0) /** - * Delete `heap[pos]` in `O(log(n))` time. + * Change `heap[pos]` to a new value @elt. The time complexity is `O(log(n))`. + * If you know that the new value is always smaller or always greater, it is faster + * to use `HEAP_DECREASE` or `HEAP_INCREASE` respectively. + **/ +#define HEAP_REPLACE(type,heap,num,less,swap,pos,elt) \ + do { \ + type _elt = elt; \ + if (less(heap[pos], _elt)) \ + HEAP_INCREASE(type,heap,num,less,swap,pos,_elt); \ + else \ + HEAP_DECREASE(type,heap,num,less,swap,pos,_elt); \ + } while(0) + +/** + * Replace the minimum `heap[pos]` by a new value @elt. The time complexity is `O(log(n))`. + **/ +#define HEAP_REPLACE_MIN(type,heap,num,less,swap,elt) \ + HEAP_INCREASE(type,heap,num,less,swap,1,elt) + +/** + * Delete an arbitrary element, given by its position. The @num variable is decremented. + * The operation takes `O(log(n))` time. **/ #define HEAP_DELETE(type,heap,num,less,swap,pos) \ do { \ - uns _j, _l, _u; \ - type x; \ - _j = pos; \ - swap(heap,_j,num,x); \ num--; \ - if (less(heap[_j], heap[num+1])) \ - HEAP_BUBBLE_UP_J(heap,num,less,swap) \ - else \ - HEAP_BUBBLE_DOWN_J(heap,num,less,swap); \ + HEAP_REPLACE(type,heap,num,less,swap,pos,heap[num+1]); \ } while(0) /**