/* * \AUTHOR: Serena Pallecchi student of Computer Science University of Pisa (Italy) * Commission from Faunalia Pontedera (PI) www.faunalia.it * * This program is free software under the GPL (>=v2) * Read the COPYING file that comes with GRASS for details. * */ #include #include #include #include #include #include "defs.h" #include "avlDefs.h" #include "avlID.h" static avlID_node *avlID_individua(const avlID_tree root, const long k, avlID_node ** father, int *direction); static int avlID_height(const avlID_tree root); static avlID_node *critical_node(avlID_node * added, int *pos1, int *pos2, const avlID_node * prec); void avlID_rotation_ll(avlID_node * critical); void avlID_rotation_lr(avlID_node * critical); void avlID_rotation_rl(avlID_node * critical); void avlID_rotation_rr(avlID_node * critical); avlID_tree avlID_make(const long k, const long n) { avlID_node *root = NULL; /* root pointer */ /* create root */ root = G_malloc(sizeof(avlID_node)); if (root == NULL) return NULL; /* initialize root */ root->right_child = NULL; root->left_child = NULL; root->father = NULL; root->counter = n; root->id = k; return root; } void avlID_destroy(avlID_tree root) { struct avlID_node *it; struct avlID_node *save = root; /* Rotate away the left links so that we can treat this like the destruction of a linked list */ while((it = save) != NULL) { if (it->left_child == NULL) { /* No left links, just kill the node and move on */ save = it->right_child; G_free(it); it = NULL; } else { /* Rotate away the left link and check again */ save = it->left_child; it->left_child = save->right_child; save->right_child = it; } } } long howManyID(const avlID_tree root, const long k) { avlID_node *nodo = NULL; nodo = avlID_find(root, k); if (nodo == NULL) return 0; else return nodo->counter; } avlID_node *avlID_find(const avlID_tree root, const long k) { avlID_node *p = NULL; int d = 0; if (root == NULL) return NULL; return avlID_individua(root, k, &p, &d); } long avlID_sub(avlID_tree * root, const long k) { long ris = 0; avlID_node *nodo = NULL; nodo = avlID_find(*root, k); if (nodo != NULL) { ris = nodo->counter; nodo->counter = 0; } return ris; } int avlID_add(avlID_tree * root, const long k, const long n) { int d = 0; /* -1 if the new node is the left child 1 if the new node is the right child */ int pos1 = 0, pos2 = 0; int rotation = 0; /* rotation type to balance tree */ avlID_node *node_temp = NULL; avlID_node *critical = NULL; avlID_node *p = NULL; /* father pointer of new node */ if ((root == NULL) || (*root == NULL)) return AVL_ERR; /* find where insert the new node */ node_temp = avlID_individua(*root, k, &p, &d); if (node_temp != NULL) { node_temp->counter = node_temp->counter + n; return AVL_PRES; /* key already exists in the tree, only update the counter */ } /* create the new node */ node_temp = avlID_make(k, n); if (node_temp == NULL) return AVL_ERR; /* insert the new node */ node_temp->father = p; if (d == -1) p->left_child = node_temp; else { if (d == 1) p->right_child = node_temp; else { G_free(node_temp); return AVL_ERR; } } /* if necessary balance the tree */ critical = critical_node(node_temp, &pos1, &pos2, NULL); if (critical == NULL) return AVL_ADD; /* not necessary */ /* balance */ rotation = (pos1 * 10) + pos2; switch (rotation) { /* rotate */ case AVL_SS: avlID_rotation_ll(critical); break; case AVL_SD: avlID_rotation_lr(critical); break; case AVL_DS: avlID_rotation_rl(critical); break; case AVL_DD: avlID_rotation_rr(critical); break; default: G_fatal_error("avl, avlID_add: balancing error\n"); return AVL_ERR; } /* if after rotation there is a new root update the root pointer */ while ((*root)->father != NULL) *root = (*root)->father; return AVL_ADD; } long avlID_to_array(avlID_node * root, long i, avlID_table * a) { if (root != NULL) { i = avlID_to_array(root->left_child, i, a); if (a == NULL) G_fatal_error("avl, avlID_to_array: null value"); else { a[i] = G_malloc(sizeof(avlID_tableRow)); a[i]->k = root->id; a[i]->tot = root->counter; i++; i = avlID_to_array(root->right_child, i, a); } } return i; } /* private functions */ static avlID_node *avlID_individua(const avlID_tree root, const long k, avlID_node ** father, int *direction) { if (root == NULL) return NULL; if (root->id == k) return root; else { if (root->id > k) { *father = root; *direction = -1; return avlID_individua(root->left_child, k, father, direction); } else { /* key < k */ *father = root; *direction = 1; return avlID_individua(root->right_child, k, father, direction); } } } static int avlID_height(const avlID_tree root) { if (root == NULL) return -1; else { int tmp1 = avlID_height(root->left_child); int tmp2 = avlID_height(root->right_child); return (1 + ((tmp1 > tmp2) ? tmp1 : tmp2)); } } static avlID_node *critical_node(avlID_node * added, int *pos1, int *pos2, const avlID_node * prec) { int fdb = 0; if (added == NULL) return NULL; if (prec == NULL) *pos1 = *pos2 = 0; else { *pos2 = *pos1; if (prec == added->left_child) *pos1 = AVL_S; else *pos1 = AVL_D; /* prec == added->right_child */ } fdb = abs(avlID_height(added->left_child) - avlID_height(added->right_child)); if (fdb > 1) return added; else { prec = added; return critical_node(added->father, pos1, pos2, prec); } } void avlID_rotation_ll(avlID_node * critical) { avlID_node *b = NULL; avlID_node *r = critical; avlID_node *s = critical->left_child; s->father = r->father; if (r->father != NULL) { if ((r->father)->left_child == r) (r->father)->left_child = s; else (r->father)->right_child = s; } b = s->right_child; s->right_child = r; r->father = s; r->left_child = b; if (b != NULL) b->father = r; } void avlID_rotation_rr(avlID_node * critical) { avlID_node *b = NULL; avlID_node *r = critical; avlID_node *s = critical->right_child; s->father = r->father; if (r->father != NULL) { if ((r->father)->left_child == r) (r->father)->left_child = s; else (r->father)->right_child = s; } b = s->left_child; s->left_child = r; r->father = s; r->right_child = b; if (b != NULL) b->father = r; } void avlID_rotation_lr(avlID_node * critical) { avlID_node *b = NULL; avlID_node *g = NULL; avlID_node *r = critical; avlID_node *s = critical->left_child; avlID_node *t = (critical->left_child)->right_child; t->father = r->father; if (r->father != NULL) { if ((r->father)->left_child == r) (r->father)->left_child = t; else (r->father)->right_child = t; } b = t->left_child; g = t->right_child; t->left_child = s; t->right_child = r; r->father = t; s->father = t; s->right_child = b; r->left_child = g; if (b != NULL) b->father = s; if (g != NULL) g->father = r; } void avlID_rotation_rl(avlID_node * critical) { avlID_node *b = NULL; avlID_node *g = NULL; avlID_node *r = critical; avlID_node *s = critical->right_child; avlID_node *t = (critical->right_child)->left_child; t->father = r->father; if (r->father != NULL) { if ((r->father)->left_child == r) (r->father)->left_child = t; else (r->father)->right_child = t; } b = t->left_child; g = t->right_child; t->left_child = r; t->right_child = s; r->father = t; s->father = t; r->right_child = b; s->left_child = g; if (b != NULL) b->father = r; if (g != NULL) g->father = s; }