/* Algorithm T of Knuth 6.2.2.2 key is pointer to a user data area containing the key and possibly more. We iterate like Knuth does, but using for(;;) instead of go-to. */ static struct ts_entry * tsearch_inner( const void *key, struct ts_entry* localrootp, int (*compar)(const void *, const void *), int*inserted) { struct ts_entry* p = localrootp; for(;;) { struct ts_entry *r = 0; /* T2. */ int kc = compar(key,p->keyptr); if(kc < 0) { /* T3. */ struct ts_entry *l = p->llink; if (l) { p = l; continue; } /* T5 */ r = tsearch_inner_do_insert(key,kc,inserted,p); return r; } else if (kc > 0 ) { /* T4. */ struct ts_entry *r2 = p->rlink; if (r2) { p = r2; continue; } /* T5 */ r = tsearch_inner_do_insert(key,kc,inserted,p); return r; } /* K = KEY(P) in Knuth. */ /* kc == 0, we found the entry we search for. */ return p; } /* Can never get here. */ return 0; }
/* Algorithm A of Knuth 6.2.3, balanced tree. key is pointer to a user data area containing the key and possibly more. We could recurse on this routine, but instead we iterate (like Knuth does, but using for(;;) instead of go-to. */ static struct ts_entry * tsearch_inner( const void *key, struct ts_entry* head, int (*compar)(const void *, const void *), int*inserted, struct ts_entry **nullme, int * comparres) { /* t points to parent of p */ struct ts_entry *t = head; /* p moves down tree, p starts as root. */ struct ts_entry *p = head->rlink; /* s points where rebalancing may be needed. */ struct ts_entry *s = p; struct ts_entry *r = 0; struct ts_entry *q = 0; int a = 0; int kc = 0; for(;;) { /* A2. */ kc = compar(key,p->keyptr); if(kc) { /* A3 and A4 handled here. */ q = getlink(p,kc); if(!q) { /* Does step A5. */ q = tsearch_inner_do_insert(key,kc,inserted,p); if (!q) { /* Out of memory. */ return q; } break; /* to A5. */ } if(q->balance) { t = p; s = q; } p = q; continue; } /* K = KEY(P) in Knuth. */ /* kc == 0, we found the entry we search for. */ return p; } /* A5: work already done. */ /* A6: */ { /* Balance factors on nodes betwen S and Q need to be changed from zero to +-1 */ int kc2 = compar(key,s->keyptr); if (kc2 < 0) { a = -1; } else { a = 1; } r = p = getlink(s,a); while (p != q) { int kc3 = compar(key,p->keyptr); if(kc3 < 0) { p->balance = -1; p = p->llink; } else if (kc3 > 0) { p->balance = 1; p = p->rlink; } else { /* ASSERT: p == q */ break; } } } /* A7: */ { if(! s->balance) { /* Tree has grown higher. */ s->balance = a; /* Counting in pointers, not integers. Ugh. */ head->llink = head->llink + 1; return q; } if(s->balance == -a) { /* Tree is more balanced */ s->balance = 0; return q; } if (s->balance == a) { /* Rebalance. */ if(r->balance == a) { /* single rotation, step A8. */ p = r; setlink(s,a,getlink(r,-a)); setlink(r,-a,s); s->balance = 0; r->balance = 0; } else if (r->balance == -a) { /* double rotation, step A9. */ p = getlink(r,-a); setlink(r,-a,getlink(p,a)); setlink(p,a,r); setlink(s,a,getlink(p,-a)); setlink(p,-a,s); if(p->balance == a) { s->balance = -a; r->balance = 0; } else if (p->balance == 0) { s->balance = 0; r->balance = 0; } else if (p->balance == -a) { s->balance = 0; r->balance = a; } p->balance = 0; } else { fprintf(stderr,"Impossible balanced tree situation!\n"); /* Impossible. Cannot be here. */ exit(1); } } else { fprintf(stderr,"Impossible balanced tree situation!!\n"); /* Impossible. Cannot be here. */ exit(1); } } /* A10: */ if (s == t->rlink) { t->rlink = p; } else { t->llink = p; } #ifdef DW_CHECK_CONSISTENCY dwarf_check_balance(head,1); #endif return q; }