diff options
Diffstat (limited to 'src/cnm/bst_pq.c')
-rw-r--r-- | src/cnm/bst_pq.c | 808 |
1 files changed, 808 insertions, 0 deletions
diff --git a/src/cnm/bst_pq.c b/src/cnm/bst_pq.c new file mode 100644 index 0000000..9502f4e --- /dev/null +++ b/src/cnm/bst_pq.c @@ -0,0 +1,808 @@ +/** + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * <http://www.gnu.org/licenses/>. + * + * (c) Vincenzo Nicosia 2009-2017 -- <v.nicosia@qmul.ac.uk> + * + * This file is part of NetBunch, a package for complex network + * analysis and modelling. For more information please visit: + * + * http://www.complex-networks.net/ + * + * If you use this software, please add a reference to + * + * V. Latora, V. Nicosia, G. Russo + * "Complex Networks: Principles, Methods and Applications" + * Cambridge University Press (2017) + * ISBN: 9781107103184 + * + *********************************************************************** + * + * This is an implementation of a Binary Search Tree augmented by a + * Priority Queue. This data structure is central to the + * implementation of the Clauset-Newman-Moore greedy modularity + * optimisation algorithm + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <assert.h> + +#include "utils.h" +#include "bst_pq.h" + + + +/* BST-related functions */ + + +void __recursive_preorder(node_t *cur, ilfunc_t *funs){ + + if(cur->left){ + __recursive_preorder(cur->left, funs); + } + if(cur -> active) + funs->print(cur->info, funs->fileout); + if(cur->right){ + __recursive_preorder(cur->right, funs); + } +} + +/* + * + * Recursive push of nodes in the nodecache :-) + * + */ + +void __recursive_destroy(node_t *cur, ilfunc_t *funs){ + if(cur->left){ + __recursive_destroy(cur->left, funs); + cur->left = NULL; + } + if(cur->right){ + __recursive_destroy(cur->right, funs); + cur->right = NULL; + } +} + + +int __recursive_insert(node_t *cur, node_t *elem, ilfunc_t *f){ + + int res ; + res = f->compare(cur->info, elem->info); + /* printf("res: %d\n", res); */ + assert(res != 0); + if ( res > 0){ + if (cur->left){ + return __recursive_insert(cur->left, elem, f); + } + else{ + cur->left = elem; + elem->parent = cur; + return 0; + } + } + else if (res < 0){ + if (cur->right){ + return __recursive_insert(cur->right, elem, f); + } + else{ + cur->right = elem; + elem->parent = cur; + return 0; + } + } + if (cur -> active){ + printf("warning!!!!! duplicate entry!!!!!!\n\n"); + exit(1); + } + else + cur->active = 1; + return -1; +} + + + +void* __recursive_lookup(node_t *cur, int v, ilfunc_t *f){ + + int res; + + res = f->compare(cur->info, v); + + if (res > 0){ + if(cur->left) + return __recursive_lookup(cur->left, v, f); + else + return NULL; + + } + else if (res < 0){ + if(cur->right) + return __recursive_lookup(cur->right, v, f); + else + return NULL; + } + else{ /* res == 0, we found the element we were looking for */ + return cur; + } +} + + + +node_t* __recursive_getmin(node_t *cur){ + + if(cur->left){ + return __recursive_getmin(cur->left); + } + else{ + return cur; + } + +} + + +node_t* __tree_getmin(node_t *n){ + + if (!n){ + return NULL; + } + else{ + return __recursive_getmin(n); + } + +} + + +/* This is used by __tree__delete to put another tree v in place of + the current node u */ + + +void __tree_transplant(bst_pq_t t, node_t *u, node_t * v){ + + if (u->parent == NULL){ + t->root = v; + } + else if(u == u->parent->left){ + u->parent->left = v; + } + else{ + u->parent->right = v; + } + if (v != NULL){ + v->parent = u->parent; + } + +} + + +void __tree_delete(bst_pq_t t, node_t *z){ + + node_t *y; + + if (z == NULL) + return; + + if (z->left == NULL){ + __tree_transplant(t, z, z->right); + } + else if(z->right == NULL){ + __tree_transplant(t, z, z->left); + } + else{ + y = __tree_getmin(z->right); + if (y->parent != z){ + __tree_transplant(t, y, y->right); + y->right = z->right; + y->right->parent = y; + } + __tree_transplant(t, z, y); + y->left = z->left; + y->left->parent = y; + } +} + + + + +void bst_pq_tree_destroy(bst_pq_t t){ + + if(t->root) + __recursive_destroy(t->root, & (t->bst_funs)); + free(t); +} + + + + +void __bst_pq_tree_view_pre(bst_pq_t t){ + + if (t->root){ + printf("----\n"); + __recursive_preorder(t->root, & (t->bst_funs)); + printf("\n----\n"); + } + else + printf("----- Empty tree!!!! -----\n"); + +} + + + +void* __bst_pq_tree_lookup(bst_pq_t t , int elem){ + + if(t->root) + return __recursive_lookup(t->root, elem, & (t->bst_funs) ); + else + return NULL; +} + + + + + +/* void bst_pq_tree_map(bst_pq_t t, void (*func)(void*)){ */ + +/* __recursive_map(t->root, func); */ + +/* } */ + + +/* void bst_pq_tree_map_args(bst_pq_t t, void (*func)(void*, void*), void *args){ */ + +/* __recursive_map_args(t->root, func, args); */ + +/* } */ + +void* bst_pq_tree_get_fileout(bst_pq_t t){ + + return t->bst_funs.fileout; +} + +void bst_pq_tree_set_fileout(bst_pq_t t, void *f){ + + t->bst_funs.fileout = f; +} + + + +node_t* __recursive_getmax(node_t *cur){ + + if(cur->right){ + return __recursive_getmax(cur->right); + } + else{ + return cur; + } + +} + + +void* bst_pq_tree_getmax(bst_pq_t t){ + + if (!t){ + return NULL; + } + else{ + return __recursive_getmax(t->root); + } + +} + + +/************************ + * PQ-related functions * + ************************/ + +void __update_handle(bst_pq_t q, int idx){ + + node_t *n; + n = (node_t*) q->v[idx]; + n->index = idx; + //q->handles[q->pq_funs.get_id(q->v[idx])] = idx; +} + + + +void __bst_pq_queue_sift_up(bst_pq_t q, int i){ + + int idx, parent; + void *tmp; + + if ( q->last < 0) + return; /* no sifting if the PQ is empty!!! */ + + idx = i; + parent = PARENT(idx); + + switch(q->qtype){ + case MAX_QUEUE: + while ( idx >0 && q->pq_funs.compare(q->v[idx]->key, q->v[parent]->key) > 0){ + tmp = q->v[idx]; + q->v[idx] = q->v[parent]; + q->v[parent] = tmp; + __update_handle(q, idx); + __update_handle(q, parent); + idx = parent; + parent = PARENT(idx); + } + break; + case MIN_QUEUE: + while ( idx >0 && q-> pq_funs.compare(q->v[idx]->key, q->v[parent]->key) < 0){ + tmp = q->v[idx]; + q->v[idx] = q->v[parent]; + q->v[parent] = tmp; + __update_handle(q, idx); + __update_handle(q, parent); + idx = parent; + parent = PARENT(idx); + } + break; + } +} + + +void __bst_pq_queue_sift_down(bst_pq_t q, int i){ + + int left, right, largest, smallest; + void *tmp; + + if ( q->last < 0) + return; /* no sifting if the PQ is empty!!! */ + if( i > q->last) + return; /* no sifting if the index i is beyond the end of the PQ */ + + switch(q->qtype){ + case MAX_QUEUE: + largest = i; + left = 2 * i + 1; + right = 2 * i + 2; + + if (left <= q->last && q->pq_funs.compare(q->v[left]->key, q->v[largest]->key) > 0){ + largest = left; + } + if (right <= q->last && q->pq_funs.compare(q->v[right]->key, q->v[largest]->key) > 0){ + largest = right; + } + if (largest != i){ + tmp = q->v[i]; + q->v[i] = q->v[largest]; + q->v[largest] = tmp; + __update_handle(q, i); + __update_handle(q, largest); + __bst_pq_queue_sift_down(q, largest); + } + else{ + __update_handle(q, i); + } + break; + + case MIN_QUEUE: + smallest = i; + left = 2 * i + 1; + right = 2 * i + 2; + + if (left <= q->last && q->pq_funs.compare(q->v[left]->key, q->v[smallest]->key) < 0){ + smallest = left; + } + if (right <= q->last && q->pq_funs.compare(q->v[right]->key, q->v[smallest]->key) < 0){ + smallest = right; + } + if (smallest != i){ + tmp = q->v[i]; + q->v[i] = q->v[smallest]; + q->v[smallest] = tmp; + __update_handle(q, i); + __update_handle(q, smallest); + __bst_pq_queue_sift_down(q, smallest); + } + else{ + __update_handle(q, i); + } + break; + } +} + + +void __bst_pq_queue_insert(bst_pq_t q, void *elem){ + + //void *tmp; + + if (q->last == q->N-1){ + /* reallocate the array to arrange a few new elements */ + q->N += 10; + q->v = realloc(q->v, (q->N) * sizeof(void*)); + VALID_PTR_OR_EXIT(q->v, 17); + //q->v = tmp; + } + + q->last += 1; + q->v[q->last] = elem; + __update_handle(q, q->last); + __bst_pq_queue_sift_up(q, q->last); + +} + + + +int __bst_pq_queue_delete_index(bst_pq_t q, int index){ + + if (q->last >=0 && index <= q->last){ + //*val = q->v[0]; + q->v[index] = q->v[q->last]; + q->last -= 1; + __bst_pq_queue_sift_down(q, index); + return 0; + } + else{ + return 1; + } +} + + + +void* __bst_pq_queue_peek(bst_pq_t q){ + + if (q->last >= 0) + return q->v[0]; + else + return NULL; +} + + + +int __bst_pq_queue_force_key(bst_pq_t q, unsigned int idx, double key){ + + switch(q->qtype){ + case MAX_QUEUE: + if (q->pq_funs.compare_to_key(q->v[idx], key) > 0){ + //q->pq_funs.set_key(q->v[idx], key); + q->v[idx]->key = key; + __bst_pq_queue_sift_down(q, idx); + } + else{ + //q->pq_funs.set_key(q->v[idx], key); + q->v[idx]->key = key; + __bst_pq_queue_sift_up(q, idx); + } + break; + case MIN_QUEUE: + if (q->pq_funs.compare_to_key(q->v[idx], key) < 0){ + //q->pq_funs.set_key(q->v[idx], key); + q->v[idx]->key = key; + __bst_pq_queue_sift_down(q, idx); + } + else{ + //q->pq_funs.set_key(q->v[idx], key); + q->v[idx]->key = key; + __bst_pq_queue_sift_up(q, idx); + } + break; + } + return 0; +} + + + +void __bst_pq_queue_dump(bst_pq_t q){ + + int i; + + unsigned int N; + + N = q->last+1; + + printf("N: %d last:%d root:", q->N, q->last); + if (q->last >=0) + q->pq_funs.print_elem(q->v[0]); + else + printf("NULL"); + printf("\n"); + + for(i=0; i<N; i++){ + if (i < (N+1)/2){ + if (2*i+1 < N) + if (2*i + 2 < N){ + printf("%d: ", i); + q->pq_funs.print_elem(q->v[i]); + printf(" ("); + q->pq_funs.print_elem(q->v[2*i+1]); + printf(", "); + q->pq_funs.print_elem(q->v[2*i+2]); + printf(")\n"); + } + else{ + printf("%d: ", i); + q->pq_funs.print_elem(q->v[i]); + printf(" ("); + q->pq_funs.print_elem(q->v[2*i+1]); + printf(", NULL)\n"); + } + else{ + printf("%d: ", i); + q->pq_funs.print_elem(q->v[i]); + printf(" (NULL, NULL)\n"); + } + } + else{ + printf("%d: ", i); + q->pq_funs.print_elem(q->v[i]); + printf(" (NULL, NULL)\n"); + } + } + printf("\n"); +} + + + + +/* bst_pq interface */ + +/* init the BST_PQ -- TESTED --*/ + +bst_pq_t bst_pq_create(ilfunc_t *bst_funs, gen_pqueue_func_t *pq_funs, char qtype, + unsigned int N, gen_stack_t *node_cache){ + + bst_pq_t b; + + b = (bst_pq_t)malloc(sizeof(bst_pq_struct_t)); + b->root = NULL; + b->bst_funs = *bst_funs; + + b->bst_funs.fileout = stdout; + b->qtype = qtype; + b->N = N; + b->last = -1; + b->pq_funs = *pq_funs; + b->v = b->pq_funs.alloc_vector(N); + if (node_cache == NULL){ + b->node_cache = malloc(sizeof(gen_stack_t)); + gen_stack_create(b->node_cache); + } + else{ + b->node_cache = node_cache; + } + return b; +} + + + + + + + +/* insert a new element in the BST_PQ -- TESTED */ +void bst_pq_insert(bst_pq_t b, unsigned int elem_info, double elem_key){ + + /* insert the element in the tree first */ + node_t *n; + int err; + + n = __bst_pq_tree_lookup(b, elem_info); + + /* The following assert should fail ONLY if there is an auto-loop */ + assert(n == NULL); + + if (gen_stack_empty(b->node_cache)){ + n = (node_t*)malloc(sizeof(node_t)); + //n->info = b->bst_funs.alloc(); + //n->key = b->pq_funs.alloc_key(); + } + else{ + err = gen_stack_pop(b->node_cache, (void**) &n); + if (err){ + n = malloc(sizeof(node_t)); + //n->info = b->bst_funs.alloc(); + //n->key = b->pq_funs.alloc_key(); + } + } + //b->bst_funs.copy(elem_info, n->info); + n->info = elem_info; + n->left = n->right = NULL; + if (b->root == NULL){ + b->root = n; + n->parent = NULL; + } + else{ + err = __recursive_insert(b->root, n, & (b->bst_funs)); + if(err){ + fprintf(stderr, "Error during insert into BST!!! (%s: %d)\n", + __FILE__, __LINE__); + exit(23); + } + } + n->active = 1; + n->index = -1; + /* set the key as needed */ + //b->pq_funs.copy_key(elem_key, n->key); + n->key = elem_key; + + /* then, insert the pointer to the element in the PQ */ + __bst_pq_queue_insert(b, n); + +} + +/* delete (or deactivate) the element associated to a given info -- TESTED --*/ +int bst_pq_delete(bst_pq_t b, unsigned int info){ + + node_t *n; + + n = __bst_pq_tree_lookup(b, info); + + if (n != NULL){ + __tree_delete(b, n); + n->active = 0; /* deactivate the node */ + /* After the node has been deleted from the tree, we add it to + the node cache */ + gen_stack_push(b->node_cache, n); + __bst_pq_queue_delete_index(b, n->index); /* remove the reference form the PQ */ + return 0; /* No problem */ + } + return 1; /* the element does not exist */ +} + +/* change the key of an element in the BST_PQ -- TESTED --*/ +int bst_pq_change_key(bst_pq_t b, unsigned int info, double key){ + + node_t *n; + int idx; + + n = __bst_pq_tree_lookup(b, info); + if (n != NULL){ + /* the element exists. We should just force its key and sift as required */ + idx = n->index; + __bst_pq_queue_force_key(b, idx, key); + return 0; /* No problem */ + } + else{ + return 1; /* The element does not exist */ + } + +} + +/* return the head of the PQ -- TESTED --*/ +void* bst_pq_peek(bst_pq_t q){ + + return __bst_pq_queue_peek(q); +} + + +/* Read the key of a given node of the BST */ +double bst_pq_get_key(bst_pq_t b, unsigned int info){ + + node_t *n; + + n = __bst_pq_tree_lookup(b, info); + if (n != NULL){ + return n->key; + } + else{ + return -100000; + } +} + + +/* Read the key of the element of index "index" in the PQ */ +double bst_pq_get_key_from_index(bst_pq_t b, int index){ + + node_t *n; + + n = (node_t *)b->v[index]; + + return n->key; +} + + +/* Dump the BST -- TESTED -- */ +void bst_pq_dump_bst(bst_pq_t b){ + + __bst_pq_tree_view_pre(b); + +} + +/* Show the PQ -- TESTED -- */ +void bst_pq_dump_pq(bst_pq_t b){ + + __bst_pq_queue_dump(b); + +} + +/* Perform a lookup of an element in the BST_PQ -- TESTED-- */ +node_t* bst_pq_lookup(bst_pq_t b, unsigned int info){ + + return __bst_pq_tree_lookup(b, info); +} + + +node_t* bst_pq_lookup_active(bst_pq_t b, unsigned int info){ + + node_t *ptr; + + ptr = __bst_pq_tree_lookup(b, info); + + if(ptr) + assert(ptr->active != 0); + + if (ptr != NULL && ptr->active){ + return ptr; + } + + return NULL; +} + + +/* void bst_pq_insert_existing(bst_pq_t b, node_t *n){ */ + +/* /\* insert the element in the tree first *\/ */ +/* if (n == NULL){ */ +/* fprintf(stderr, "Error!!!! Attempt to insert a NULL existing element (%s: %d)\n", */ +/* __FILE__, __LINE__); */ +/* exit(37); */ +/* } */ +/* /\* n->info = b->bst_funs.alloc(); *\/ */ +/* /\* n->key = b->pq_funs.alloc_key(); *\/ */ +/* /\* b->bst_funs.copy(elem_info, n->info); *\/ */ +/* n->left = n->right = NULL; */ +/* if (b->root == NULL){ */ +/* b->root = n; */ +/* n->parent = NULL; */ +/* } */ +/* else{ */ +/* __recursive_insert(b->root, n, & (b->bst_funs)); */ +/* } */ + +/* n->active = 1; */ +/* /\* set the key as needed *\/ */ +/* //b->pq_funs.copy_key(elem_key, n->key); */ + +/* /\* then, insert the pointer to the element in the PQ *\/ */ +/* __bst_pq_queue_insert(b, n); */ + +/* } */ + + + + + + +void bst_pq_destroy(bst_pq_t b, char destroy_cache){ + + int i; + node_t *n; + + if (b == NULL) + return; + + if(destroy_cache && b->node_cache != NULL ){ + while(!gen_stack_pop(b->node_cache, (void**) &n)){ + //b->bst_funs.dealloc(n->info); + //free(n->key); + free(n); + } + free(b->node_cache->v); + free(b->node_cache); + } + + for(i=b->last; i>=0; i--){ + __tree_delete(b, b->v[i]); + __bst_pq_queue_delete_index(b, i); /* remove the reference form the PQ */ + //bst_pq_delete(b, b->v[i]->info); + //b->bst_funs.dealloc(b->v[i]->info); + //free(b->v[i]->key); + free(b->v[i]); + } + free(b->v); + free(b); +} |