/* Returns deleted node parent unless the head changed. Returns NULL if wanted node not found or the tree is now empty or the head node changed. Sets *did_delete if it found and deleted a node. Sets *tree_empty if there are no more user nodes present. */ static struct ts_entry * tdelete_inner(const void *key, struct ts_entry *head, int (*compar)(const void *, const void *), int *tree_empty, int *did_delete ) { struct ts_entry *p = 0; struct ts_entry *pp = 0; struct pkrecord * pkarray = 0; int depth = head->llink - (struct ts_entry *)0; unsigned k = 0; /* Allocate extra, head is on the stack we create here and the depth might increase. */ depth = depth + 4; pkarray = calloc(sizeof(struct pkrecord),depth); if(!pkarray) { /* Malloc fails, we could abort... */ return NULL; } k = 0; pkarray[k].pk=head; pkarray[k].ak=1; p = head->rlink; while(p) { int kc = 0; k++; kc = compar(key,p->keyptr); pkarray[k].pk = p; pkarray[k].ak = kc; if(!kc) { break; } p = getlink(p,kc); } if(!p) { /* Node to delete never found. */ free(pkarray); return NULL; } { struct ts_entry *t = 0; struct ts_entry *r = 0; int pak = 0; int ppak = 0; p = pkarray[k].pk; pak = pkarray[k].ak; pp = pkarray[k-1].pk; ppak = pkarray[k-1].ak; /* Found a match. p to be deleted. */ t = p; *did_delete = 1; if(!t->rlink) { if(k == 1 && !t->llink) { *tree_empty = 1; /* upper level will fix up head node. */ free(t); free(pkarray); return NULL; } /* t->llink might be NULL. */ setlink(pp,ppak,t->llink); /* ASSERT: t->llink NULL or t->llink has no children, balance zero and balance of t->llink not changing. */ k--; /* Step D4. */ free(t); goto balance; } #ifdef IMPLEMENTD15 /* Step D1.5 */ if(!t->llink) { setlink(pp,ppak,t->rlink); /* we change the left link off ak */ k--; /* Step D4. */ free(t); goto balance; } #endif /* IMPLEMENTD15 */ /* Step D2 */ r = t->rlink; if (!r->llink) { /* We decrease the height of the right tree. */ r->llink = t->llink; setlink(pp,ppak,r); pkarray[k].pk = r; pkarray[k].ak = 1; /* The following essential line not mentioned in Knuth AFAICT. */ r->balance = t->balance; /* Step D4. */ free(t); goto balance; } /* Step D3, we rearrange the tree and pkarray so the balance step can work. step D2 is insufficient so not done. */ k = rearrange_tree_so_p_llink_null(pkarray,k, head,r, p,pak,pp,ppak); goto balance; } /* Now use pkarray decide if rebalancing needed and, if needed, to rebalance. k here matches l-1 in Knuth. */ balance: { unsigned k2 = k; /* We do not want a test in the for() itself. */ for( ; 1 ; k2--) { struct ts_entry *pk = 0; int ak = 0; int bk = 0; if (k2 == 0) { /* decreased in height */ head->llink--; goto cleanup; } pk = pkarray[k2].pk; if (!pk) { /* Nothing here to work with. Move up. */ continue; } ak = pkarray[k2].ak; bk = pk->balance; if(bk == ak) { pk->balance = 0; continue; } if(bk == 0) { pk->balance = -ak; goto cleanup; } /* ASSERT: bk == -ak. We will use bk == adel here (just below). */ /* Rebalancing required. Here we use (1) and (2) in 6.2.3 to adjust the nodes */ { /* Rebalance. We use s for what is called A in Knuth Case 1, Case 2 page 461. r For what is called B. So the link movement logic looks similar to the tsearch insert case.*/ struct ts_entry *r = 0; struct ts_entry *s = 0; struct ts_entry *pa = 0; int pak = 0; int adel = -ak; s = pk; r = getlink(s,adel); pa = pkarray[k2-1].pk; pak = pkarray[k2-1].ak; if(r->balance == adel) { /* case 1. */ setlink(s,adel,getlink(r,-adel)); setlink(r,-adel,s); /* A10 in tsearch. */ setlink(pa,pak,r); s->balance = 0; r->balance = 0; continue; } else if (r->balance == -adel) { /* case 2 */ /* x plays the role of p in step A9 */ struct ts_entry*x = getlink(r,-adel); setlink(r,-adel,getlink(x,adel)); setlink(x,adel,r); setlink(s,adel,getlink(x,-adel)); setlink(x,-adel,s); /* A10 in tsearch. */ setlink(pa,pak,x); if(x->balance == adel) { s->balance = -adel; r->balance = 0; } else if (x->balance == 0) { s->balance = 0; r->balance = 0; } else if (x->balance == -adel) { s->balance = 0; r->balance = adel; } x->balance = 0; continue; } else { /* r->balance == 0 case 3 we do a single rotation and we are done. */ setlink(s,adel,getlink(r,-adel)); setlink(r,-adel,s); setlink(pa,pak,r); r->balance = -adel; /*s->balance = r->balance = 0; */ goto cleanup; } } } } cleanup: free(pkarray); #ifdef DW_CHECK_CONSISTENCY dwarf_check_balance(head,1); #endif return pp; }
/* * list merge sorting * Donald E Knuth, "The Art of Computer Programming", * Vol.3 / Sorting & Searching, pp. 165-166, Algorithm L. */ global List *sortlist(List *p, int (*compar)()) { List xh, yh, *xp, *yp, *x, *y; unsigned n, xn, yn; /* L1. Separate list p into 2 lists. */ xp = &xh; yp = &yh; while (p != NULL) { xp->next = p; xp = p; p = p->next; if (p == NULL) break; yp->next = p; yp = p; p = p->next; } xp->next = NULL; yp->next = NULL; for (n = 1; yh.next != NULL; n *= 2) { /* L2. Begin new pass. */ xp = &xh; yp = &yh; x = xp->next; y = yp->next; xn = yn = n; do { /* L3. Compare */ if (compar(x, y) <= 0) { /* L4. Advance x. */ xp->next = x; xp = x; x = x->next; if (--xn != 0 && x != NULL) continue; /* L5. Complete the sublist. */ xp->next = y; xp = yp; do { yp = y; y = y->next; } while (--yn != 0 && y != NULL); } else { /* L6. Advance y. */ xp->next = y; xp = y; y = y->next; if (--yn != 0 && y != NULL) continue; /* L7. Complete the sublist. */ xp->next = x; xp = yp; do { yp = x; x = x->next; } while (--xn != 0 && x != NULL); } xn = yn = n; /* L8. End of pass? */ } while (y != NULL); xp->next = x; yp->next = NULL; } return xh.next; }
void * dwarf_tdelete(const void *key, void **headin, int (*compar)(const void *, const void *)) { struct ts_entry *phead = 0; struct ts_entry **rootp = 0; struct ts_entry *root = 0; struct ts_entry *p = 0; /* If a leaf is found, we have to null a parent link or the root */ struct ts_entry * parentp = 0; int parentcomparv = 0; int done = 0; if (!headin) { return NULL; } phead = (struct ts_entry *)*headin; if (!phead) { return NULL; } rootp = &phead->rlink; root = phead->rlink; if (!root) { return NULL; } p = root; while(p) { int kc = compar(key,p->keyptr); if (!kc) { break; } parentp = p; parentcomparv = kc; p = getlink(p,kc); } if(!p) { return NULL; } { /* In Knuth Algorithm D, the parenthetical comment "(For example, if Q===RLINK(P) for some P we would set RLINK(P)<- LLINK(T).)" informs us that Q is assumed to be a conceptual name for some RLINK or LLINK, not a C local variable. In the rest of this algorithm variables can be ordinary C pointers, but not true for Q. Hence in the following we use *q to set Q. */ struct ts_entry **q = 0; struct ts_entry *t = 0; struct ts_entry *r = 0; struct ts_entry *s = 0; int emptied_a_leaf = 0; /* Either we found root (to remove) or we have a parentp and the parent mismatched the key so parentcomparv is != 0 */ if (p == root) { q = rootp; } else if (parentcomparv < 0) { q = &parentp->llink; } else /* (parentcomparv > 0) */ { q = &parentp->rlink; } /* D1. Here *q is what Knuth calls q. */ t = *q; r = t->rlink; if (!r) { *q = t->llink; done = 1; } else { /* D2. */ if (!r->llink) { r->llink = t->llink; *q = r; done = 1; } } while (!done) { /* D3. */ s = r->llink; if(s->llink) { r = s; continue; } s->llink = t->llink; r->llink = s->rlink; s->rlink = t->rlink; *q = s; done = 1; } /* Step D4. */ if(!t->llink && !t->rlink) { emptied_a_leaf = 1; } free(t); if(emptied_a_leaf) { if (p == root) { /* The tree is completely empty now. Free the special head node. Notify the caller. */ free(phead); *headin = 0; return NULL; } } if(!parentp) { /* The item we found was at top of tree, found == root. We have a new root node. We return it, there is no parent. Other than one might say, the fake parent phead (with only rlink, but that has no key so we ignore). */ return (void *)(&(root->keyptr)); } return (void *)(&(parentp->keyptr)); } return NULL; }
/* 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, UNUSEDARG struct ts_entry **nullme, UNUSEDARG 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; }
void * dwarf_tdelete(const void *key, void **headin, int (*compar)(const void *, const void *)) { struct ts_entry *phead = 0; struct ts_entry **rootp = 0; struct ts_entry *root = 0; struct ts_entry * p= 0; /* If a leaf is found, we have to null a parent link or the root */ struct ts_entry * parentp = 0; int parentcomparv = 0; int done = 0; /* We don't really care much if multiple tree tables use this simultaneously. This left/right is a practical thing not supported by known theory, according to Knuth. We start with eppingerleftr=1 because that happens to show a different tree than standard knuth in one of our standard tsearch regression test sequences. */ static unsigned eppingerleft = 1; if (!headin) { return NULL; } phead = (struct ts_entry *)*headin; if (!phead) { return NULL; } rootp = &phead->rlink; root = phead->rlink; if (!root) { return NULL; } p = root; while(p) { int kc = compar(key,p->keyptr); if (!kc) { break; } parentp = p; parentcomparv = kc; p = getlink(p,kc); } if(!p) { return NULL; } { struct ts_entry **q = 0; struct ts_entry *t = 0; struct ts_entry *s = 0; int emptied_a_leaf = 0; /* Either we found root (to remove) or we have a parentp and the parent mismatched the key so parentcomparv is != 0 */ if (p == root) { q = rootp; } else if (parentcomparv < 0) { q = &parentp->llink; } else /* (parentcomparv > 0) */ { q = &parentp->rlink; } /* D1. *q is what Knuth calls q. */ t = *q; if(!eppingerleft) { struct ts_entry *r = 0; eppingerleft = 1; r = t->rlink; if (!r) { *q = t->llink; done = 1; } else { /* D2. */ if (!r->llink) { r->llink = t->llink; *q = r; done = 1; } } while (!done) { /* D3. */ s = r->llink; if(s->llink) { r = s; continue; } s->llink = t->llink; r->llink = s->rlink; s->rlink = t->rlink; *q = s; done = 1; } } else { struct ts_entry *l = 0; eppingerleft = 0; l = t->llink; if (!l) { *q = t->rlink; done = 1; } else { /* D2. */ if (!l->rlink) { l->rlink = t->rlink; *q = l; done = 1; } } while (!done) { /* D3. */ s = l->rlink; if(s->rlink) { l = s; continue; } s->rlink = t->rlink; l->rlink = s->llink; s->llink = t->llink; *q = s; done = 1; } } /* Step D4. */ if(!t->llink && !t->rlink) { emptied_a_leaf = 1; } free(t); if(emptied_a_leaf) { if (p == root) { /* The tree is completely empty now. Free the special head node. Notify the caller. */ free(phead); *headin = 0; return NULL; } } if(!parentp) { /* The item we found was at top of tree, found == root. We have a new root node. We return it, there is no parent. */ return (void *)(&(root->keyptr)); } return (void *)(&(parentp->keyptr)); } return NULL; }
static int rel_lt(const char *text, size_t tlen, const char *pat, void *rock) { compare_t compar = (compare_t) rock; return (compar(text, tlen, pat) < 0); }
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { char *i; char *j; size_t thresh = T * size; char *base_ = (char *)base; char *limit = base_ + nmemb * size; PREPARE_STACK; for (;;) { if ((size_t)(limit - base_) > thresh) { /* QSort for more than T elements. */ /* We work from second to last - first will be pivot element. */ i = base_ + size; j = limit - size; /* We swap first with middle element, then sort that with second and last element so that eventually first element is the median of the three - avoiding pathological pivots. TODO: Instead of middle element, chose one randomly. */ memswp(((((size_t)(limit - base_)) / size) / 2) * size + base_, base_, size); if (compar(i, j) > 0) { memswp(i, j, size); } if (compar(base_, j) > 0) { memswp(base_, j, size); } if (compar(i, base_) > 0) { memswp(i, base_, size); } /* Now we have the median for pivot element, entering main Quicksort. */ for (;;) { do { /* move i right until *i >= pivot */ i += size; } while (compar(i, base_) < 0); do { /* move j left until *j <= pivot */ j -= size; } while (compar(j, base_) > 0); if (i > j) { /* break loop if pointers crossed */ break; } /* else swap elements, keep scanning */ memswp(i, j, size); } /* move pivot into correct place */ memswp(base_, j, size); /* larger subfile base / limit to stack, sort smaller */ if (j - base_ > limit - i) { /* left is larger */ PUSH(base_, j); base_ = i; } else { /* right is larger */ PUSH(i, limit); limit = j; } } else { /* insertion sort for less than T elements */ for (j = base_, i = j + size; i < limit; j = i, i += size) { for (; compar(j, j + size) > 0; j -= size) { memswp(j, j + size, size); if (j == base_) { break; } } } if (stackptr != stack) { /* if any entries on stack */ POP(base_, limit); } else { /* else stack empty, done */ break; } } } }
void parallel_merge(int master, int ncpu, size_t * nlist, size_t nmax, char *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *)) { size_t na, nb, nr; int cpua, cpub, cpur; char *list_a, *list_b, *list_r; int NTask; int ThisTask; MPI_Comm_rank(MPI_COMM_WORLD, &ThisTask); MPI_Comm_size(MPI_COMM_WORLD, &NTask); if(master + ncpu / 2 >= NTask) /* nothing to do */ return; if(ThisTask != master) { if(nmemb) { list_r = (char *) malloc(nmemb * size); MPI_Request requests[2]; MPI_Isend(base, nmemb * size, MPI_BYTE, master, TAG_DATAIN, MPI_COMM_WORLD, &requests[0]); MPI_Irecv(list_r, nmemb * size, MPI_BYTE, master, TAG_DATAOUT, MPI_COMM_WORLD, &requests[1]); MPI_Waitall(2, requests, MPI_STATUSES_IGNORE); memcpy(base, list_r, nmemb * size); free(list_r); } } else { list_a = (char *) malloc(nmax * size); list_b = (char *) malloc(nmax * size); list_r = (char *) malloc(nmax * size); cpua = master; cpub = master + ncpu / 2; cpur = master; na = 0; nb = 0; nr = 0; memcpy(list_a, base, nmemb * size); if(nlist[cpub]) MPI_Recv(list_b, nlist[cpub] * size, MPI_BYTE, cpub, TAG_DATAIN, MPI_COMM_WORLD, MPI_STATUS_IGNORE); while(cpur < master + ncpu && cpur < NTask) { while(na >= nlist[cpua] && cpua < master + ncpu / 2 - 1) { cpua++; if(nlist[cpua]) MPI_Recv(list_a, nlist[cpua] * size, MPI_BYTE, cpua, TAG_DATAIN, MPI_COMM_WORLD, MPI_STATUS_IGNORE); na = 0; } while(nb >= nlist[cpub] && cpub < master + ncpu - 1 && cpub < NTask - 1) { cpub++; if(nlist[cpub]) MPI_Recv(list_b, nlist[cpub] * size, MPI_BYTE, cpub, TAG_DATAIN, MPI_COMM_WORLD, MPI_STATUS_IGNORE); nb = 0; } while(nr >= nlist[cpur]) { if(cpur == master) memcpy(base, list_r, nr * size); else { if(nlist[cpur]) MPI_Send(list_r, nlist[cpur] * size, MPI_BYTE, cpur, TAG_DATAOUT, MPI_COMM_WORLD); } nr = 0; cpur++; if(cpur >= master + ncpu) break; } if(na < nlist[cpua] && nb < nlist[cpub]) { if(compar(list_a + na * size, list_b + nb * size) < 0) { memcpy(list_r + nr * size, list_a + na * size, size); na++; nr++; } else { memcpy(list_r + nr * size, list_b + nb * size, size); nb++; nr++; } } else if(na < nlist[cpua]) { memcpy(list_r + nr * size, list_a + na * size, size); na++; nr++; } else if(nb < nlist[cpub]) { memcpy(list_r + nr * size, list_b + nb * size, size); nb++; nr++; } } free(list_r); free(list_b); free(list_a); } }
int test_call(int a, int b, int compar(int x, int y)) { return compar(a, b); }
void gmx_qsort(void * base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { #define QSORT_EXCH(a, b, t) (t = a, a = b, b = t) #define QSORT_SWAP(a, b) swaptype != 0 ? qsort_swapfunc(a, b, size, swaptype) : \ (void)QSORT_EXCH(*(int *)(a), *(int *)(b), t) char *pa, *pb, *pc, *pd, *pl, *pm, *pn, *pv, *cbase; int r, swaptype; int t, v; size_t s, st; cbase = (char *)base; swaptype = (size_t)(cbase - (char *)0) % sizeof(int) || size % sizeof(int) ? 2 : size == sizeof(int) ? 0 : 1; if (nmemb < 7) { /* Insertion sort on smallest arrays */ for (pm = cbase + size; pm < cbase + nmemb*size; pm += size) { for (pl = pm; (pl > cbase) && compar((void *)(pl-size), (void *) pl) > 0; pl -= size) { QSORT_SWAP(pl, pl-size); } } return; } /* Small arrays, middle element */ pm = cbase + (nmemb/2)*size; if (nmemb > 7) { pl = cbase; pn = cbase + (nmemb-1)*size; if (nmemb > 40) { /* Big arrays, pseudomedian of 9 */ s = (nmemb/8)*size; pl = (char *)qsort_med3((void *)pl, (void *)((size_t)pl+s), (void *)((size_t)pl+2*s), compar); pm = (char *)qsort_med3((void *)((size_t)pm-s), (void *)pm, (void *)((size_t)pm+s), compar); pn = (char *)qsort_med3((void *)((size_t)pn-2*s), (void *)((size_t)pn-s), (void *)pn, compar); } /* Mid-size, med of 3 */ pm = (char *)qsort_med3((void *)pl, (void *)pm, (void *)pn, compar); } /* pv points to partition value */ if (swaptype != 0) { pv = cbase; QSORT_SWAP(pv, pm); } else { pv = (char*)(void*)&v; v = *(int *)pm; } pa = pb = cbase; pc = pd = cbase + (nmemb-1)*size; for (;; ) { while (pb <= pc && (r = compar((void *)pb, (void *) pv)) <= 0) { if (r == 0) { QSORT_SWAP(pa, pb); pa += size; } pb += size; } while (pc >= pb && (r = compar((void *)pc, (void *) pv)) >= 0) { if (r == 0) { QSORT_SWAP(pc, pd); pd -= size; } pc -= size; } if (pb > pc) { break; } QSORT_SWAP(pb, pc); pb += size; pc -= size; } pn = cbase + nmemb*size; s = pa-cbase; st = pb-pa; if (st < s) { s = st; } if (s > 0) { qsort_swapfunc(cbase, pb-s, s, swaptype); } s = pd-pc; st = pn-pd-size; if (st < s) { s = st; } if (s > 0) { qsort_swapfunc(pb, pn-s, s, swaptype); } if ((s = pb-pa) > size) { gmx_qsort(cbase, s/size, size, compar); } if ((s = pd-pc) > size) { gmx_qsort(pn-s, s/size, size, compar); } #undef QSORT_EXCH #undef QSORT_SWAP return; }
/* Delete a node from the tree */ int rbtn_del(rbtn_t **root, int key, void* data, int (*compar)(void*, void*), int sortbykey, int nofixup) { rbtn_t *x, *y, *z; int c; char color; z = (*root == NULL) ? RBTN_NIL : *root; while (z != RBTN_NIL) { c = (sortbykey) ? (key - z->key) : compar(data, z->data); if (c == 0) break; else z = (c < 0) ? z->left : z->right; } if (z == RBTN_NIL) return 0; if ((z->left == RBTN_NIL) || (z->right == RBTN_NIL)) y = z; else { y = z->right; while (y->left != RBTN_NIL) y = y->left; } if (y->left != RBTN_NIL) x = y->left; else x = y->right; x->parent = y->parent; if (y->parent) { if (y == y->parent->left) y->parent->left = x; else y->parent->right = x; } else *root = x; color = y->color; if (y != z) { y->left = z->left; y->right = z->right; y->parent = z->parent; if (z->parent) { if (z->parent->left == z) z->parent->left = y; else z->parent->right = y; } else *root = y; y->right->parent = y; y->left->parent = y; y->color = z->color; } X_FREE(z); if ((color == RBTN_BLACK) && (!nofixup)) rbtn_delfix(root, x); return 1; }
DLLSYM inT32 choose_nth_item ( //fast median inT32 index, //index to choose void *array, //array of items inT32 count, //no of items size_t size, //element size //comparator int (*compar) (const void *, const void *) ) { int result; //of compar inT32 next_sample; //next one to do inT32 next_lesser; //space for new inT32 prev_greater; //last one saved inT32 equal_count; //no of equal ones inT32 pivot; //proposed median if (count <= 1) return 0; if (count == 2) { if (compar (array, (char *) array + size) < 0) { return index >= 1 ? 1 : 0; } else { return index >= 1 ? 0 : 1; } } if (index < 0) index = 0; //ensure lergal else if (index >= count) index = count - 1; pivot = (inT32) (rand () % count); swap_entries (array, size, pivot, 0); next_lesser = 0; prev_greater = count; equal_count = 1; for (next_sample = 1; next_sample < prev_greater;) { result = compar ((char *) array + size * next_sample, (char *) array + size * next_lesser); if (result < 0) { swap_entries (array, size, next_lesser++, next_sample++); //shuffle } else if (result > 0) { prev_greater--; swap_entries(array, size, prev_greater, next_sample); } else { equal_count++; next_sample++; } } if (index < next_lesser) return choose_nth_item (index, array, next_lesser, size, compar); else if (index < prev_greater) return next_lesser; //in equal bracket else return choose_nth_item (index - prev_greater, (char *) array + size * prev_greater, count - prev_greater, size, compar) + prev_greater; }
/* tree23_insert() - Inserts an item into the 2-3 tree pointed to by t, * according the the value its key. The key of an item in the 2-3 tree must * be unique among items in the tree. If an item with the same key already * exists in the tree, a pointer to that item is returned. Otherwise, NULL is * returned, indicating insertion was successful. */ void *tree23_insert(tree23_t *t, void *item) { int (* compar)(const void *, const void *); int cmp_result; void *key_item1, *key_item2, *temp_item, *x_min, *return_item; tree23_node_t *new_node, *x, *p; tree23_node_t **stack; int tos; signed char *path_info; p = t->root; compar = t->compar; /* Special case: only zero or one items in the tree already. */ if(t->n <= 1) { if(t->n == 0) { /* 0 items --> 1 item */ t->min_item = p->left.item = item; } else { /* 1 item --> 2 items */ cmp_result = compar(item, p->left.item); /* Check that an item with the same key does not already exist. */ if(cmp_result == 0) return p->left.item; /* else */ /* Determine insertion position. */ if(cmp_result > 0) { /* Insert as middle child. */ p->key_item1 = p->middle.item = item; } else { /* Insert as left child. */ p->key_item1 = p->middle.item = p->left.item; t->min_item = p->left.item = item; } } t->n++; return NULL; /* Insertion successful. */ } /* Stacks for storing the sequence of nodes traversed when * locating the insertion position. */ stack = t->stack; path_info = t->path_info; tos = 0; /* Search the tree to locate the insertion position. */ while(p->link_kind != LEAF_LINK) { stack[tos] = p; if(p->key_item2 && compar(item, p->key_item2) >= 0) { p = p->right.node; path_info[tos] = 1; } else if(compar(item, p->key_item1) >= 0) { p = p->middle.node; path_info[tos] = 0; } else { p = p->left.node; path_info[tos] = -1; } tos++; } key_item1 = p->key_item1; key_item2 = p->key_item2; /* Insert at the leaf items of node p. Note that key_item1 is the same as * p->middle.item and key_item2 is the same as p->right.item. */ if(key_item2 && (cmp_result = compar(item, key_item2)) >= 0) { /* Insert beside right branch. */ /* Check if the same key already exists. */ if(cmp_result == 0) { return key_item2; /* Insertion failed. */ } /* else */ /* Create a new node. Node p's right child becomes the left child * of the new node. The inserted item is the middle child of the * new node. */ new_node = malloc(sizeof(tree23_node_t)); new_node->link_kind = LEAF_LINK; new_node->left.item = p->right.item; new_node->key_item1 = new_node->middle.item = item; new_node->key_item2 = new_node->right.item = NULL; p->key_item2 = p->right.item = NULL; /* Insertion for new_node will continue higher up in the tree. */ } else if((cmp_result = compar(item, key_item1)) >= 0) { /* Insert beside the middle branch. */ /* Check if the same key already exists. */ if(cmp_result == 0) { return key_item1; /* Insertion failed. */ } /* else */ /* Insertion depends on the number of children node p currently has. */ if(key_item2) { /* Node p has three children. */ /* Create a new node. The inserted item is the left child of * the new node. Node p's right child becomes the middle * child of the new node. */ new_node = malloc(sizeof(tree23_node_t)); new_node->link_kind = LEAF_LINK; new_node->left.item = item; new_node->key_item1 = new_node->middle.item = p->right.item; new_node->key_item2 = new_node->right.item = NULL; p->key_item2 = p->right.item = NULL; /* Insertion for new_node will continue higher up in the tree. */ } else { /* Node p has two children. */ /* The item is inserted as the right child of node p. */ p->key_item2 = p->right.item = item; /* No need to insert higher up. */ t->n++; return NULL; /* Insertion successful. */ } } else { /* Insert beside the left branch. */ /* Account for the special case, where the item being inserted is * smaller than any other item in the tree. */ if((cmp_result = compar(item, p->left.item)) <= 0) { /* Check if the same key already exists in the tree. */ if(cmp_result == 0) { return p->left.item; /* Insertion failed. */ } /* else */ /* The item being inserted is smaller than any other item in the * tree. Treat p's left child as the item begin inserted. This * done by replacing p's left child with the item being inserted. */ temp_item = item; item = p->left.item; t->min_item = p->left.item = temp_item; } /* Insertion depends on the number of children node p currently has. */ if(key_item2) { /* Node p has three children. */ /* Create a new node. Node p's middle child becomes the left * child of the new node. Node p's right child becomes the middle * child of the new node. The item being inserted becomes the * middle child of node p. */ new_node = malloc(sizeof(tree23_node_t)); new_node->link_kind = LEAF_LINK; new_node->left.item = p->middle.item; new_node->key_item1 = new_node->middle.item = p->right.item; new_node->key_item2 = new_node->right.item = NULL; p->key_item1 = p->middle.item = item; p->key_item2 = p->right.item = NULL; /* Insertion for new_node will continue higher up in the tree. */ } else { /* Node p has two children. */ /* The middle child of node p becomes node p's right child, and * the item being inserted becomes the middle child. */ p->key_item2 = p->right.item = p->middle.item; p->key_item1 = p->middle.item = item; /* No need to insert higher up. */ t->n++; return NULL; /* Insertion successful. */ } } return_item = NULL; /* Insertion successful. */ t->n++; /* x points to the node being inserted into the tree. x_min keeps track of * the minimum item in the subtree rooted at the node x. */ x = new_node; x_min = new_node->left.item; /* Insertion of new nodes can keep propagating up one level in the tree. * This stops when an insertion does not result in a new node at the next * level up, or the root level (tos == 0) is reached. */ while(tos) { p = stack[--tos]; /* p is the parent node for x. */ /* Determine the insertion position of x under p. */ if(path_info[tos] > 0) { /* Insert beside the right branch. */ /* Create a new node. Node p's right child becomes the left child * of the new node. Node x is the middle child of the new node. */ new_node = malloc(sizeof(tree23_node_t)); new_node->link_kind = INTERNAL_LINK; new_node->left.node = p->right.node; new_node->middle.node = x; new_node->key_item1 = x_min; new_node->right.node = NULL; new_node->key_item2 = NULL; x_min = p->key_item2; p->right.node = NULL; p->key_item2 = NULL; /* Insertion for new_node will continue higher up in the tree. */ } else if(path_info[tos] == 0) { /* Insert beside the middle branch. */ /* Insertion depends on the number of children node p currently * has. */ if(p->key_item2) { /* Node p has three children. */ /* Create a new node. Node x is the left child of the new * node. Node p's right child becomes the middle child of the * new node. */ new_node = malloc(sizeof(tree23_node_t)); new_node->link_kind = INTERNAL_LINK; new_node->left.node = x; /* x_min does not change. */ new_node->middle.node = p->right.node; new_node->key_item1 = p->key_item2; new_node->right.node = NULL; new_node->key_item2 = NULL; p->right.node = NULL; p->key_item2 = NULL; /* Insertion for new_node will continue higher up in the tree. */ } else { /* Node p has two children. */ /* Node x is inserted as the right child of node p. */ p->right.node = x; p->key_item2 = x_min; /* No need to insert higher up. */ return return_item; } } else { /* Insert beside the left branch. */ /* Insertion depends on the number of children node p currently * has. */ if(p->key_item2) { /* Node p has three children. */ /* Create a new node. Node p's middle child becomes the left * child of the new node. Node p's right child becomes the * middle child of the new node. Node x becomes the middle * child of node p. */ new_node = malloc(sizeof(tree23_node_t)); new_node->link_kind = INTERNAL_LINK; new_node->left.node = p->middle.node; new_node->middle.node = p->right.node; new_node->key_item1 = p->key_item2; new_node->right.node = NULL; new_node->key_item2 = NULL; p->middle.node = x; temp_item = p->key_item1; p->key_item1 = x_min; x_min = temp_item; p->right.node = NULL; p->key_item2 = NULL; /* Insertion for new_node will continue higher up in the tree. */ } else { /* Node p has two children. */ /* The middle child of node p becomes node p's right child, and * node x becomes the middle child. */ p->right.node = p->middle.node; p->key_item2 = p->key_item1; p->middle.node = x; p->key_item1 = x_min; /* No need to insert higher up. */ return return_item; } } x = new_node; } /* This point is only reached if the root node was split. A new root node * will be created, with the child nodes pointed to by p (old root node) * and x (inserted node). */ new_node = malloc(sizeof(tree23_node_t)); new_node->link_kind = INTERNAL_LINK; new_node->left.node = p; new_node->middle.node = x; new_node->key_item1 = x_min; new_node->right.node = NULL; new_node->key_item2 = NULL; t->root = new_node; return return_item; }
/* tree23_delete() - Delete the item in the 2-3 tree with the same key as * the item pointed to by `key_item'. Returns a pointer to the deleted item, * and NULL if no item was found. */ void *tree23_delete(tree23_t *t, void *key_item) { int (* compar)(const void *, const void *); int cmp_result; void *key_item1, *key_item2, *return_item, *merge_item; void **min_key_ptr; tree23_node_t *p, *q, *parent, *merge_node; tree23_node_t **stack; int tos; signed char *path_info; p = t->root; compar = t->compar; /* Special cases: 0, 1, or 2 items in the tree. */ if(t->n <= 2) { if(t->n <= 1) { if(t->n == 0) { return NULL; /* Tree empty. Delete failed. */ } /* else: one item in the tree... */ /* Check if the item is the left child. */ if(compar(key_item, p->left.item) == 0) { return_item = p->left.item; /* Item found. */ t->min_item = p->left.item = NULL; t->n--; return return_item; } /* else */ return NULL; /* Item not found. */ } /* else: two items in the tree... */ /* Check if the item may be the middle child. */ if((cmp_result = compar(key_item, p->middle.item)) >= 0) { /* check if the item is the middle child. */ if(cmp_result == 0) { return_item = p->middle.item; /* Item found. */ p->key_item1 = p->middle.item = NULL; t->n--; return return_item; } /* else */ return NULL; /* Item not found. */ } /* Check if the item is the left child. */ if(compar(key_item, p->left.item) == 0) { return_item = p->left.item; /* Item found. */ t->min_item = p->left.item = p->key_item1; p->key_item1 = p->middle.item = NULL; t->n--; return return_item; } /* else */ return NULL; /* Item not found. */ } /* Allocate stacks for storing information about the path from the root * to the node to be deleted. */ stack = t->stack; path_info = t->path_info; tos = 0; min_key_ptr = NULL; /* Search the tree to locate the node pointing to the leaf item to be * deleted from the 2-3 tree. */ while(p->link_kind != LEAF_LINK) { stack[tos] = p; if(p->key_item2 && compar(key_item, p->key_item2) >= 0) { min_key_ptr = &p->key_item2; p = p->right.node; path_info[tos] = 1; } else if(compar(key_item, p->key_item1) >= 0) { min_key_ptr = &p->key_item1; p = p->middle.node; path_info[tos] = 0; } else { p = p->left.node; path_info[tos] = -1; } tos++; } key_item1 = p->key_item1; key_item2 = p->key_item2; /* Delete the appropriate leaf item of node p. Note that key_item1 is the * same as p->middle.item and key_item2 is the same as p->right.item. */ if(key_item2 && (cmp_result = compar(key_item, key_item2)) >= 0) { /* Item may be right child. */ /* Check whether the item to be deleted was found. */ if(cmp_result) { /* Item not found. */ return_item = NULL; } else { /* Item found. */ return_item = key_item2; t->n--; p->key_item2 = p->right.item = NULL; } /* No need for merge since node p still has two items. */ return return_item; } else if((cmp_result = compar(key_item, key_item1)) >= 0) { /* Item may be middle child. */ /* Check whether the item to be deleted was found. */ if(cmp_result) { /* Item not found. */ return NULL; } /* else */ return_item = key_item1; /* Item found. */ t->n--; /* If node p has three children, two are left after the delete, and no * further rearrangement is needed. */ if(key_item2) { p->key_item1 = p->middle.item = key_item2; p->key_item2 = p->right.item = NULL; return return_item; } /* else */ /* Node p has only its left child remaining. The remaining child will * be merged with a child from a sibling of node p. */ merge_item = p->left.item; } else { /* Item may be left child. */ if(compar(key_item, p->left.item)) { /* Delete failed - matching item does not exist in the tree. */ return NULL; } return_item = p->left.item; /* item found. */ t->n--; /* Check if a key in the tree changes after deletion. */ if(min_key_ptr) { *min_key_ptr = p->middle.item; /* Change key. */ } else { t->min_item = key_item1; /* Minimum node in the tree changes. */ } /* If node p has three children, two are left after the delete, and no * further rearrangement is needed. */ if(key_item2) { p->left.item = key_item1; p->key_item1 = p->middle.item = key_item2; p->key_item2 = p->right.item = NULL; return return_item; } /* else */ /* Node p has only its middle child remaining. The remaining child * will be merged with a child from a sibling of node p. */ merge_item = p->middle.item; } /* If the function has not exited by this point, then the remaining child * item of node p is to be merged with a child from a sibling of node p. * Node p is not the root node, since this falls under the special case * delete (handled at the start of this function). */ parent = stack[--tos]; /* Node p's parent. */ /* The following code performs the leaf level merging of merge_item. Note * that unless node p was a left child, it always has a sibling to its * left. */ if(path_info[tos] > 0) { /* p was the right child. */ q = parent->middle.node; /* Sibling to the left of node p. */ /* Merging depends on how many children node q currently has. */ if(q->key_item2) { /* Node q has three children. */ /* Keep node p by assigning it the right child of q as the sibling * of merge_item. */ parent->key_item2 = p->left.item = q->key_item2; p->key_item1 = p->middle.item = merge_item; q->key_item2 = q->right.item = NULL; return return_item; /* Node p is not deleted. */ } else { /* Node q has two children. */ /* Make merge_item a child of node q, and delete p. */ q->key_item2 = q->right.item = merge_item; parent->right.node = NULL; parent->key_item2 = NULL; free(p); return return_item; /* The parent still has two children. */ } } else if(path_info[tos] == 0) { /* p was the middle child. */ q = parent->left.node; /* Sibling to the left of node p. */ /* Merging depends on how many children node q currently has. */ if(q->key_item2) { /* Node q has three children. */ /* Keep node p by assigning it the right child of q as the sibling * of merge_item. */ parent->key_item1 = p->left.item = q->key_item2; p->key_item1 = p->middle.item = merge_item; q->key_item2 = q->right.item = NULL; return return_item; /* Node p is not deleted. */ } else { /* Node q has two children. */ /* Make merge_item a child of node q, and delete p. */ q->key_item2 = q->right.item = merge_item; free(p); /* If the parent of p and q had three children, then two will be * left after the merge, and merging will not be needed at the next * level up. */ if(parent->key_item2) { parent->middle.node = parent->right.node; parent->key_item1 = parent->key_item2; parent->right.node = NULL; parent->key_item2 = NULL; return return_item; } /* else */ /* The parent only has child q remaining. The remaining child * will be merged with a child from a sibling of the parent. */ merge_node = q; p = parent; } } else { /* p was the left child. */ q = parent->middle.node; /* Sibling to the right of node p. */ /* Merging depends on how many children node q currently has. */ if(q->key_item2) { /* Node q has three children. */ /* Keep node p by assigning it the left child of q as the sibling * of merge_item. */ p->left.item = merge_item; p->key_item1 = p->middle.item = q->left.item; parent->key_item1 = q->left.item = q->key_item1; q->key_item1 = q->middle.item = q->key_item2; q->key_item2 = q->right.item = NULL; return return_item; } else { /* Node q has two children. */ /* Make merge_item a child of node q, and delete p. */ q->key_item2 = q->right.item = q->key_item1; q->key_item1 = q->middle.item = q->left.item; q->left.item = merge_item; free(p); /* If the parent of p and q had three children, then two will be * left after the merge, and merging will not be needed at the next * level up. */ if(parent->key_item2) { parent->left.node = q; parent->middle.node = parent->right.node; parent->key_item1 = parent->key_item2; parent->right.node = NULL; parent->key_item2 = NULL; return return_item; } /* else */ /* The parent only has child q remaining. The remaining child * will be merged with a child from a sibling of the parent. */ merge_node = q; p = parent; } } /* Merging of nodes can keep propagating up one level in the tree. This * stops when the result of a merge does not require a merge at the next * level up, or the root level (tos == 0) is reached. */ while(tos) { /* The following code merges node p's single child, merge_node, with * a children from node p's sibling, q. */ parent = stack[--tos]; /* Node p's parent. */ /* Merging depends on which child p is. */ if(path_info[tos] > 0) { /* p was the right child. */ q = parent->middle.node; /* Sibling to the left of node p. */ /* Merging depends on how many children node q currently has. */ if(q->key_item2) { /* Node q has three children. */ /* Keep node p by assigning it the right child of q as the * sibling of merge_node. */ p->left.node = q->right.node; p->middle.node = merge_node; p->key_item1 = parent->key_item2; /* merge_min */ parent->key_item2 = q->key_item2; q->right.node = NULL; q->key_item2 = NULL; return return_item; /* Node p is not deleted. */ } else { /* Node q has two children. */ /* Make merge_node a child of node q, and delete p. */ q->right.node = merge_node; q->key_item2 = parent->key_item2; /* merge_min */ parent->right.node = NULL; parent->key_item2 = NULL; free(p); return return_item; /* The parent still has two children. */ } } else if(path_info[tos] == 0) { /* p was the middle child. */ q = parent->left.node; /* Sibling to the left of node p. */ /* Merging depends on how many children node q currently has. */ if(q->key_item2) { /* Node q has three children. */ /* Keep node p by assigning it the right child of q as the * sibling of merge_node. */ p->left.node = q->right.node; p->middle.node = merge_node; p->key_item1 = parent->key_item1; /* merge_min */ parent->key_item1 = q->key_item2; q->right.node = NULL; q->key_item2 = NULL; return return_item; /* p is not deleted. */ } else { /* Node q has two children. */ /* Make merge_node a child of node q, and delete p. */ q->right.node = merge_node; q->key_item2 = parent->key_item1; /* merge_min */ free(p); /* If the parent of p and q had three children, then two will * be left after the merge, and merging will not be needed at * the next level up. */ if(parent->key_item2) { parent->middle.node = parent->right.node; parent->key_item1 = parent->key_item2; parent->right.node = NULL; parent->key_item2 = NULL; return return_item; } /* else */ /* The parent only has child q remaining. The remaining child * will be merged with a child from a sibling of the parent. */ merge_node = q; p = parent; } } else { /* p was the left child. */ q = parent->middle.node; /* Sibling to the right of node p. */ /* Merging depends on how many children node q currently has. */ if(q->key_item2) { /* Node q has three children. */ /* Keep node p by assigning it the left child of q as the * sibling of merge_node. */ p->left.node = merge_node; p->middle.node = q->left.node; p->key_item1 = parent->key_item1; /* Equals minimum item in tree(q->left.node). */ q->left.node = q->middle.node; parent->key_item1 = q->key_item1; q->middle.node = q->right.node; q->key_item1 = q->key_item2; q->right.node = NULL; q->key_item2 = NULL; return return_item; } else { /* Node q has two children. */ /* Make merge_node a child of node q, and delete p. */ q->right.node = q->middle.node; q->key_item2 = q->key_item1; q->middle.node = q->left.node; q->key_item1 = parent->key_item1; /* Equals minimum item in tree(q->left.node). */ q->left.node = merge_node; free(p); /* If the parent of p and q had three children, then two will * be left after the merge, and merging will not be needed at * the next level up. */ if(parent->key_item2) { parent->left.node = q; parent->middle.node = parent->right.node; parent->key_item1 = parent->key_item2; parent->right.node = NULL; parent->key_item2 = NULL; return return_item; } /* else */ /* The parent only has child q remaining. The remaining child * will be merged with a child from a sibling of the parent. */ merge_node = q; p = parent; } } } /* Remove the old root node, p, making node merge_node the new root node. */ free(p); t->root = merge_node; return return_item; }
/* tree23_find() - Find an item in the 2-3 tree with the same key as the * item pointed to by `key_item'. Returns a pointer to the item found, or NULL * if no item was found. */ void *tree23_find(tree23_t *t, void *key_item) { int (* compar)(const void *, const void *); int cmp_result; tree23_node_t *p; void *key_item1, *key_item2; p = t->root; compar = t->compar; /* First check for the special cases where the tree contains contains only * zero or one nodes. */ if(t->n <= 1) { if(t->n && (compar(key_item, p->left.item) == 0)) return p->left.item; /* else */ return NULL; } /* Search the tree to locate the item with key key_item. */ while(p->link_kind != LEAF_LINK) { if(p->key_item2 && compar(key_item, p->key_item2) >= 0) { p = p->right.node; } else if(compar(key_item, p->key_item1) >= 0) { p = p->middle.node; } else { p = p->left.node; } } key_item1 = p->key_item1; key_item2 = p->key_item2; /* Find a leaf item of node p. Note key_item1 is the same as * p->middle.item and key_item2 is the same as p->right.item. */ if(key_item2 && (cmp_result = compar(key_item, key_item2)) >= 0) { /* Item may be right child. */ if(cmp_result) { /* Find failed - matching item does not exist in the tree. */ return NULL; } /* else */ return key_item2; /* Item found. */ } else if((cmp_result = compar(key_item, key_item1)) >= 0) { /* Item may be middle child. */ if(cmp_result) { /* Find failed - Matching item does not exist in the tree. */ return NULL; } /* else */ return key_item1; /* Item found. */ } else { /* Item may be left child. */ if(compar(key_item, p->left.item)) { /* Find failed - matching item does not exist in the tree. */ return NULL; } /* else */ return p->left.item; /* item found. */ } }