1570af302Sopenharmony_ci#include <stdlib.h> 2570af302Sopenharmony_ci#include <search.h> 3570af302Sopenharmony_ci#include "tsearch.h" 4570af302Sopenharmony_ci 5570af302Sopenharmony_cistatic inline int height(struct node *n) { return n ? n->h : 0; } 6570af302Sopenharmony_ci 7570af302Sopenharmony_cistatic int rot(void **p, struct node *x, int dir /* deeper side */) 8570af302Sopenharmony_ci{ 9570af302Sopenharmony_ci struct node *y = x->a[dir]; 10570af302Sopenharmony_ci struct node *z = y->a[!dir]; 11570af302Sopenharmony_ci int hx = x->h; 12570af302Sopenharmony_ci int hz = height(z); 13570af302Sopenharmony_ci if (hz > height(y->a[dir])) { 14570af302Sopenharmony_ci /* 15570af302Sopenharmony_ci * x 16570af302Sopenharmony_ci * / \ dir z 17570af302Sopenharmony_ci * A y / \ 18570af302Sopenharmony_ci * / \ --> x y 19570af302Sopenharmony_ci * z D /| |\ 20570af302Sopenharmony_ci * / \ A B C D 21570af302Sopenharmony_ci * B C 22570af302Sopenharmony_ci */ 23570af302Sopenharmony_ci x->a[dir] = z->a[!dir]; 24570af302Sopenharmony_ci y->a[!dir] = z->a[dir]; 25570af302Sopenharmony_ci z->a[!dir] = x; 26570af302Sopenharmony_ci z->a[dir] = y; 27570af302Sopenharmony_ci x->h = hz; 28570af302Sopenharmony_ci y->h = hz; 29570af302Sopenharmony_ci z->h = hz+1; 30570af302Sopenharmony_ci } else { 31570af302Sopenharmony_ci /* 32570af302Sopenharmony_ci * x y 33570af302Sopenharmony_ci * / \ / \ 34570af302Sopenharmony_ci * A y --> x D 35570af302Sopenharmony_ci * / \ / \ 36570af302Sopenharmony_ci * z D A z 37570af302Sopenharmony_ci */ 38570af302Sopenharmony_ci x->a[dir] = z; 39570af302Sopenharmony_ci y->a[!dir] = x; 40570af302Sopenharmony_ci x->h = hz+1; 41570af302Sopenharmony_ci y->h = hz+2; 42570af302Sopenharmony_ci z = y; 43570af302Sopenharmony_ci } 44570af302Sopenharmony_ci *p = z; 45570af302Sopenharmony_ci return z->h - hx; 46570af302Sopenharmony_ci} 47570af302Sopenharmony_ci 48570af302Sopenharmony_ci/* balance *p, return 0 if height is unchanged. */ 49570af302Sopenharmony_ciint __tsearch_balance(void **p) 50570af302Sopenharmony_ci{ 51570af302Sopenharmony_ci struct node *n = *p; 52570af302Sopenharmony_ci int h0 = height(n->a[0]); 53570af302Sopenharmony_ci int h1 = height(n->a[1]); 54570af302Sopenharmony_ci if (h0 - h1 + 1u < 3u) { 55570af302Sopenharmony_ci int old = n->h; 56570af302Sopenharmony_ci n->h = h0<h1 ? h1+1 : h0+1; 57570af302Sopenharmony_ci return n->h - old; 58570af302Sopenharmony_ci } 59570af302Sopenharmony_ci return rot(p, n, h0<h1); 60570af302Sopenharmony_ci} 61570af302Sopenharmony_ci 62570af302Sopenharmony_civoid *tsearch(const void *key, void **rootp, 63570af302Sopenharmony_ci int (*cmp)(const void *, const void *)) 64570af302Sopenharmony_ci{ 65570af302Sopenharmony_ci if (!rootp) 66570af302Sopenharmony_ci return 0; 67570af302Sopenharmony_ci 68570af302Sopenharmony_ci void **a[MAXH]; 69570af302Sopenharmony_ci struct node *n = *rootp; 70570af302Sopenharmony_ci struct node *r; 71570af302Sopenharmony_ci int i=0; 72570af302Sopenharmony_ci a[i++] = rootp; 73570af302Sopenharmony_ci for (;;) { 74570af302Sopenharmony_ci if (!n) 75570af302Sopenharmony_ci break; 76570af302Sopenharmony_ci int c = cmp(key, n->key); 77570af302Sopenharmony_ci if (!c) 78570af302Sopenharmony_ci return n; 79570af302Sopenharmony_ci a[i++] = &n->a[c>0]; 80570af302Sopenharmony_ci n = n->a[c>0]; 81570af302Sopenharmony_ci } 82570af302Sopenharmony_ci r = malloc(sizeof *r); 83570af302Sopenharmony_ci if (!r) 84570af302Sopenharmony_ci return 0; 85570af302Sopenharmony_ci r->key = key; 86570af302Sopenharmony_ci r->a[0] = r->a[1] = 0; 87570af302Sopenharmony_ci r->h = 1; 88570af302Sopenharmony_ci /* insert new node, rebalance ancestors. */ 89570af302Sopenharmony_ci *a[--i] = r; 90570af302Sopenharmony_ci while (i && __tsearch_balance(a[--i])); 91570af302Sopenharmony_ci return r; 92570af302Sopenharmony_ci} 93