/* * dAVLInsert: * Create a new node and insert an item there. * * Returns 0 on success, * -1 on malloc failure, * 3 if duplicate key. */ int dAVLInsert (dAVLTree *avltree, uint32 uid, char *ip4, char *ip6, char *loc) { dAVLNode *newnode; dAVLNode *node; dAVLNode *balnode; dAVLNode *nextbalnode; newnode = malloc(sizeof(dAVLNode)); if (newnode == NULL) return -1; newnode->key = uid; byte_copy(newnode->ip4, 4, ip4); byte_copy(newnode->ip6, 16, ip6); byte_copy(newnode->loc, 16, loc); newnode->depth = 1; newnode->left = NULL; newnode->right = NULL; newnode->parent = NULL; if (avltree->top != NULL) { node = dAVLCloseSearchNode(avltree, newnode->key); /* XXX: handle this more intelligent */ if (node->key == newnode->key) { free(newnode); return 3; } newnode->parent = node; if (newnode->key < node->key) { node->left = newnode; node->depth = CALC_DEPTH(node); } else { node->right = newnode; node->depth = CALC_DEPTH(node); } for (balnode = node->parent; balnode; balnode = nextbalnode) { nextbalnode = balnode->parent; dAVLRebalanceNode(avltree, balnode); } } else { avltree->top = newnode; } avltree->count++; return 0; }
/* * avl_rebalance: * Rebalances the tree if one side becomes too heavy. This function * assumes that both subtrees are AVL-trees with consistant data. The * function has the additional side effect of recalculating the count of * the tree at this node. It should be noted that at the return of this * function, if a rebalance takes place, the top of this subtree is no * longer going to be the same node. */ static void avl_rebalance(avl_tree_t *avltree, avl_node_t *avlnode) { avl_node_t *child; avl_node_t *gchild; avl_node_t *parent; avl_node_t **superparent; parent = avlnode; while(avlnode) { parent = avlnode->parent; superparent = parent ? avlnode == parent->left ? &parent->left : &parent->right : &avltree->top; switch(avl_check_balance(avlnode)) { case -1: child = avlnode->left; #ifdef AVL_DEPTH if(L_DEPTH(child) >= R_DEPTH(child)) { #else #ifdef AVL_COUNT if(L_COUNT(child) >= R_COUNT(child)) { #else #error No balancing possible. #endif #endif avlnode->left = child->right; if(avlnode->left) avlnode->left->parent = avlnode; child->right = avlnode; avlnode->parent = child; *superparent = child; child->parent = parent; #ifdef AVL_COUNT avlnode->count = CALC_COUNT(avlnode); child->count = CALC_COUNT(child); #endif #ifdef AVL_DEPTH avlnode->depth = CALC_DEPTH(avlnode); child->depth = CALC_DEPTH(child); #endif } else { gchild = child->right; avlnode->left = gchild->right; if(avlnode->left) avlnode->left->parent = avlnode; child->right = gchild->left; if(child->right) child->right->parent = child; gchild->right = avlnode; if(gchild->right) gchild->right->parent = gchild; gchild->left = child; if(gchild->left) gchild->left->parent = gchild; *superparent = gchild; gchild->parent = parent; #ifdef AVL_COUNT avlnode->count = CALC_COUNT(avlnode); child->count = CALC_COUNT(child); gchild->count = CALC_COUNT(gchild); #endif #ifdef AVL_DEPTH avlnode->depth = CALC_DEPTH(avlnode); child->depth = CALC_DEPTH(child); gchild->depth = CALC_DEPTH(gchild); #endif } break; case 1: child = avlnode->right; #ifdef AVL_DEPTH if(R_DEPTH(child) >= L_DEPTH(child)) { #else #ifdef AVL_COUNT if(R_COUNT(child) >= L_COUNT(child)) { #else #error No balancing possible. #endif #endif avlnode->right = child->left; if(avlnode->right) avlnode->right->parent = avlnode; child->left = avlnode; avlnode->parent = child; *superparent = child; child->parent = parent; #ifdef AVL_COUNT avlnode->count = CALC_COUNT(avlnode); child->count = CALC_COUNT(child); #endif #ifdef AVL_DEPTH avlnode->depth = CALC_DEPTH(avlnode); child->depth = CALC_DEPTH(child); #endif } else { gchild = child->left; avlnode->right = gchild->left; if(avlnode->right) avlnode->right->parent = avlnode; child->left = gchild->right; if(child->left) child->left->parent = child; gchild->left = avlnode; if(gchild->left) gchild->left->parent = gchild; gchild->right = child; if(gchild->right) gchild->right->parent = gchild; *superparent = gchild; gchild->parent = parent; #ifdef AVL_COUNT avlnode->count = CALC_COUNT(avlnode); child->count = CALC_COUNT(child); gchild->count = CALC_COUNT(gchild); #endif #ifdef AVL_DEPTH avlnode->depth = CALC_DEPTH(avlnode); child->depth = CALC_DEPTH(child); gchild->depth = CALC_DEPTH(gchild); #endif } break; default: #ifdef AVL_COUNT avlnode->count = CALC_COUNT(avlnode); #endif #ifdef AVL_DEPTH avlnode->depth = CALC_DEPTH(avlnode); #endif } avlnode = parent; } } /*------------------------------------------------------------------------------ end of functions from AVL-tree library. *******************************************************************************/ #if !defined(VARIANT) || VARIANT < 1 || VARIANT > 4 #error VARIANT must be either 1, 2, 3 or 4, e.g., 'make VARIANT=4' #endif #if __GNUC__ >= 3 # define __hv_unused __attribute__ ((unused)) #else # define __hv_unused /* no 'unused' attribute available */ #endif #if VARIANT < 3 # define __variant3_only __hv_unused #else # define __variant3_only #endif #if VARIANT < 2 # define __variant2_only __hv_unused #else # define __variant2_only #endif typedef struct dlnode { double *x; /* The data vector */ struct dlnode **next; /* Next-node vector */ struct dlnode **prev; /* Previous-node vector */ struct avl_node_t * tnode; int ignore; int ignore_best; //used in define_order #if VARIANT >= 2 double *area; /* Area */ #endif #if VARIANT >= 3 double *vol; /* Volume */ #endif } dlnode_t; static avl_tree_t *tree; #if VARIANT < 4 int stop_dimension = 1; /* default: stop on dimension 2 */ #else int stop_dimension = 2; /* default: stop on dimension 3 */ #endif static int compare_node(const void *p1, const void* p2) { const double x1 = *((*(const dlnode_t **)p1)->x); const double x2 = *((*(const dlnode_t **)p2)->x); return (x1 < x2) ? -1 : (x1 > x2) ? 1 : 0; } static int compare_tree_asc(const void *p1, const void *p2) { const double *x1 = (const double *)p1; const double *x2 = (const double *)p2; return (x1[1] > x2[1]) ? -1 : (x1[1] < x2[1]) ? 1 : (x1[0] >= x2[0]) ? -1 : 1; } /* * Setup circular double-linked list in each dimension */ static dlnode_t * setup_cdllist(double *data, int d, int n) { dlnode_t *head; dlnode_t **scratch; int i, j; head = malloc ((n+1) * sizeof(dlnode_t)); head->x = data; head->ignore = 0; /* should never get used */ head->next = malloc( d * (n+1) * sizeof(dlnode_t*)); head->prev = malloc( d * (n+1) * sizeof(dlnode_t*)); head->tnode = malloc ((n+1) * sizeof(avl_node_t)); #if VARIANT >= 2 head->area = malloc(d * (n+1) * sizeof(double)); #endif #if VARIANT >= 3 head->vol = malloc(d * (n+1) * sizeof(double)); #endif for (i = 1; i <= n; i++) { head[i].x = head[i-1].x + d;/* this will be fixed a few lines below... */ head[i].ignore = 0; head[i].next = head[i-1].next + d; head[i].prev = head[i-1].prev + d; head[i].tnode = head[i-1].tnode + 1; #if VARIANT >= 2 head[i].area = head[i-1].area + d; #endif #if VARIANT >= 3 head[i].vol = head[i-1].vol + d; #endif } head->x = NULL; /* head contains no data */ scratch = malloc(n * sizeof(dlnode_t*)); for (i = 0; i < n; i++) scratch[i] = head + i + 1; for (j = d-1; j >= 0; j--) { for (i = 0; i < n; i++) scratch[i]->x--; qsort(scratch, n, sizeof(dlnode_t*), compare_node); head->next[j] = scratch[0]; scratch[0]->prev[j] = head; for (i = 1; i < n; i++) { scratch[i-1]->next[j] = scratch[i]; scratch[i]->prev[j] = scratch[i-1]; } scratch[n-1]->next[j] = head; head->prev[j] = scratch[n-1]; } free(scratch); for (i = 1; i <= n; i++) { (head[i].tnode)->item = head[i].x; } return head; } static void free_cdllist(dlnode_t * head) { free(head->tnode); /* Frees _all_ nodes. */ free(head->next); free(head->prev); #if VARIANT >= 2 free(head->area); #endif #if VARIANT >= 3 free(head->vol); #endif free(head); }
/* * dAVLRebalanceNode: * Rebalances the AVL tree if one side becomes too heavy. This function * assumes that both subtrees are AVL trees with consistant data. This * function has the additional side effect of recalculating the depth of * the tree at this node. It should be noted that at the return of this * function, if a rebalance takes place, the top of this subtree is no * longer going to be the same node. */ void dAVLRebalanceNode (dAVLTree *avltree, dAVLNode *avlnode) { long depthdiff; dAVLNode *child; dAVLNode *gchild; dAVLNode *origparent; dAVLNode **superparent; origparent = avlnode->parent; if (origparent) { if (avlnode->key < avlnode->parent->key) superparent = &(avlnode->parent->left); else superparent = &(avlnode->parent->right); } else superparent = &(avltree->top); depthdiff = R_DEPTH(avlnode) - L_DEPTH(avlnode); if (depthdiff <= -2) { child = avlnode->left; if (L_DEPTH(child) >= R_DEPTH(child)) { avlnode->left = child->right; if (avlnode->left != NULL) avlnode->left->parent = avlnode; avlnode->depth = CALC_DEPTH(avlnode); child->right = avlnode; if (child->right != NULL) child->right->parent = child; child->depth = CALC_DEPTH(child); *superparent = child; child->parent = origparent; } else { gchild = child->right; avlnode->left = gchild->right; if (avlnode->left != NULL) avlnode->left->parent = avlnode; avlnode->depth = CALC_DEPTH(avlnode); child->right = gchild->left; if (child->right != NULL) child->right->parent = child; child->depth = CALC_DEPTH(child); gchild->right = avlnode; if (gchild->right != NULL) gchild->right->parent = gchild; gchild->left = child; if (gchild->left != NULL) gchild->left->parent = gchild; gchild->depth = CALC_DEPTH(gchild); *superparent = gchild; gchild->parent = origparent; } } else if (depthdiff >= 2) { child = avlnode->right; if (R_DEPTH(child) >= L_DEPTH(child)) { avlnode->right = child->left; if (avlnode->right != NULL) avlnode->right->parent = avlnode; avlnode->depth = CALC_DEPTH(avlnode); child->left = avlnode; if (child->left != NULL) child->left->parent = child; child->depth = CALC_DEPTH(child); *superparent = child; child->parent = origparent; } else { gchild = child->left; avlnode->right = gchild->left; if (avlnode->right != NULL) avlnode->right->parent = avlnode; avlnode->depth = CALC_DEPTH(avlnode); child->left = gchild->right; if (child->left != NULL) child->left->parent = child; child->depth = CALC_DEPTH(child); gchild->left = avlnode; if (gchild->left != NULL) gchild->left->parent = gchild; gchild->right = child; if (gchild->right != NULL) gchild->right->parent = gchild; gchild->depth = CALC_DEPTH(gchild); *superparent = gchild; gchild->parent = origparent; } } else { avlnode->depth = CALC_DEPTH(avlnode); } }