static LTI *aa_find(LTI **t,char *name,int len,int *insert) { // find/insert node into t LTI *lti=NULL; int iter=(*insert)&ITER; int dir=(*insert)&1; if ((*t)==&aa_sentinel) lti=((*insert)&INSERT)?(*t)=LTI_init(NEW(LTI),name,len):NULL; else { int delta=0; for (int i=0;delta==0 && i<PREVIEWLEN && i<len && i<(*t)->len;i++) delta=name[i]-(*t)->preview[i]; if (!delta) // preview matched, compare full strings delta=strnncmp(name,len,(*t)->name,(*t)->len); int deltadir=delta<0?LEFT:RIGHT; // turn LTZ/Z/GTZ into left/right/right if (delta) { if (LTI_invalid(lti=aa_find(&(*t)->lnk[deltadir],name,len,insert)) && iter && dir!=deltadir) lti=*t; } else if (iter) // matches, but find next smaller/larger lti=aa_most((*t)->lnk[dir],!dir); else // return match lti=(*t),(*insert)=0; } if ((*insert)&INSERT) { // rebalance if necessary aa_skew(t); aa_split(t); } return lti; }
// remove is non-aa-canonical... // a: traverse down to leaf, looking for matches along the way // b: if there's a match, clip leaf and return thru to matching node // c: matching node swaps, and then returns matching node to caller static LTI *aa_remove(LTI **t,char *name,int len,int match) { LTI *result=NULL; if (LTI_invalid(*t)) return &aa_sentinel; // descend tree, finding matching node ("toremove") and then "next-greater" leaf ("tokeep") int delta=0; for (int i=0;delta==0 && i<PREVIEWLEN && i<len && i<(*t)->len;i++) delta=name[i]-(*t)->preview[i]; if (!delta) // preview matched, compare full strings delta=strnncmp(name,len,(*t)->name,(*t)->len); result=aa_remove(&(*t)->lnk[delta<0?LEFT:RIGHT],name,len,match|!delta); if (!delta) { // matching node if (result!=&aa_sentinel) { // swap with leaf... result->lnk[LEFT]=(*t)->lnk[LEFT]; result->lnk[RIGHT]=(*t)->lnk[RIGHT]; (*t)->lnk[LEFT]=&aa_sentinel; (*t)->lnk[RIGHT]=&aa_sentinel; } LTI *newresult=(*t); (*t)=result; result=newresult; } else if (match && result==&aa_sentinel) { result=*t; *t=&aa_sentinel; } cleanup: // on the way back, re rebalance if (!LTI_invalid(*t)) { if (((*t)->lnk[LEFT]->level < ((*t)->level-1)) || ((*t)->lnk[RIGHT]->level < ((*t)->level-1))) { (*t)->level--; if ((*t)->lnk[RIGHT]->level > (*t)->level) (*t)->lnk[RIGHT]->level = (*t)->level; aa_skew(t); aa_skew(&(*t)->lnk[RIGHT]); aa_skew(&(*t)->lnk[RIGHT]->lnk[RIGHT]); aa_split(t); aa_split(&(*t)->lnk[RIGHT]); } } done: return result; }
static aa_node * aa_delete_r(aa_tree *tree, aa_node **nodep, void *key) { aa_node *node, *pred, *succ; void *ret; int cmp; ret = NULL; if ((node = *nodep) == &aa_nil) { return (NULL); } else if ((cmp = tree->compare(key, node->data)) == 0) { if (node->left == &aa_nil && node->right == &aa_nil) { ret = node->data; aa_free(node); *nodep = &aa_nil; tree->size--; return (ret); } else if (node->left == &aa_nil) { succ = node->right; while (succ->left != &aa_nil) succ = succ->left; node->data = succ->data; ret = aa_delete_r(tree, &node->right, succ->data); } else { pred = node->left; while (pred->right != &aa_nil) pred = pred->right; node->data = pred->data; ret = aa_delete_r(tree, &node->left, pred->data); } } else if (cmp < 0) { ret = aa_delete_r(tree, &node->left, key); } else /* (cmp > 0) */ { ret = aa_delete_r(tree, &node->right, key); } if (node->left->level < node->level - 1 || node->right->level < node->level - 1) node->level = node->level - 1; node = aa_skew(node); node->right = aa_skew(node->right); node->right->right = aa_skew(node->right->right); node = aa_split(node); node->right = aa_split(node->right); *nodep = node; return (ret); }