⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tree234.c

📁 用来作为linux中SIP SERVER,完成VOIP网络电话中服务器的功能
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Find an element e in a sorted 2-3-4 tree t. Returns NULL if not * found. e is always passed as the first argument to cmp, so cmp * can be an asymmetric function if desired. cmp can also be passed * as NULL, in which case the compare function from the tree proper * will be used. */void *findrelpos234(tree234 *t, void *e, cmpfn234 cmp,		    int relation, int *index) {    node234 *n;    void *ret;    int c;    int idx, ecount, kcount, cmpret;    if (t->root == NULL)	return NULL;    if (cmp == NULL)	cmp = t->cmp;    n = t->root;    /*     * Attempt to find the element itself.     */    idx = 0;    ecount = -1;    /*     * Prepare a fake `cmp' result if e is NULL.     */    cmpret = 0;    if (e == NULL) {	assert(relation == REL234_LT || relation == REL234_GT);	if (relation == REL234_LT)	    cmpret = +1;	       /* e is a max: always greater */	else if (relation == REL234_GT)	    cmpret = -1;	       /* e is a min: always smaller */    }    while (1) {	for (kcount = 0; kcount < 4; kcount++) {	    if (kcount >= 3 || n->elems[kcount] == NULL ||		(c = cmpret ? cmpret : cmp(e, n->elems[kcount])) < 0) {		break;	    }	    if (n->kids[kcount]) idx += n->counts[kcount];	    if (c == 0) {		ecount = kcount;		break;	    }	    idx++;	}	if (ecount >= 0)	    break;	if (n->kids[kcount])	    n = n->kids[kcount];	else	    break;    }    if (ecount >= 0) {	/*	 * We have found the element we're looking for. It's	 * n->elems[ecount], at tree index idx. If our search	 * relation is EQ, LE or GE we can now go home.	 */	if (relation != REL234_LT && relation != REL234_GT) {	    if (index) *index = idx;	    return n->elems[ecount];	}	/*	 * Otherwise, we'll do an indexed lookup for the previous	 * or next element. (It would be perfectly possible to	 * implement these search types in a non-counted tree by	 * going back up from where we are, but far more fiddly.)	 */	if (relation == REL234_LT)	    idx--;	else	    idx++;    } else {	/*	 * We've found our way to the bottom of the tree and we	 * know where we would insert this node if we wanted to:	 * we'd put it in in place of the (empty) subtree	 * n->kids[kcount], and it would have index idx	 * 	 * But the actual element isn't there. So if our search	 * relation is EQ, we're doomed.	 */	if (relation == REL234_EQ)	    return NULL;	/*	 * Otherwise, we must do an index lookup for index idx-1	 * (if we're going left - LE or LT) or index idx (if we're	 * going right - GE or GT).	 */	if (relation == REL234_LT || relation == REL234_LE) {	    idx--;	}    }    /*     * We know the index of the element we want; just call index234     * to do the rest. This will return NULL if the index is out of     * bounds, which is exactly what we want.     */    ret = index234(t, idx);    if (ret && index) *index = idx;    return ret;}void *find234(tree234 *t, void *e, cmpfn234 cmp) {    return findrelpos234(t, e, cmp, REL234_EQ, NULL);}void *findrel234(tree234 *t, void *e, cmpfn234 cmp, int relation) {    return findrelpos234(t, e, cmp, relation, NULL);}void *findpos234(tree234 *t, void *e, cmpfn234 cmp, int *index) {    return findrelpos234(t, e, cmp, REL234_EQ, index);}/* * Delete an element e in a 2-3-4 tree. Does not free the element, * merely removes all links to it from the tree nodes. */static void *delpos234_internal(tree234 *t, int index) {    node234 *n;    void *retval;    int ei = -1;    retval = 0;    n = t->root;    LOG123(("deleting item %d from tree %p\n", index, t));    while (1) {	while (n) {	    int ki;	    node234 *sub;	    LOG123(("  node %p: %p/%d [%p] %p/%d [%p] %p/%d [%p] %p/%d index=%d\n",		 n,		 n->kids[0], n->counts[0], n->elems[0],		 n->kids[1], n->counts[1], n->elems[1],		 n->kids[2], n->counts[2], n->elems[2],		 n->kids[3], n->counts[3],		 index));	    if (index < n->counts[0]) {		ki = 0;	    } else if (index -= n->counts[0]+1, index < 0) {		ei = 0; break;	    } else if (index < n->counts[1]) {		ki = 1;	    } else if (index -= n->counts[1]+1, index < 0) {		ei = 1; break;	    } else if (index < n->counts[2]) {		ki = 2;	    } else if (index -= n->counts[2]+1, index < 0) {		ei = 2; break;	    } else {		ki = 3;	    }	    /*	     * Recurse down to subtree ki. If it has only one element,	     * we have to do some transformation to start with.	     */	    LOG123(("  moving to subtree %d\n", ki));	    sub = n->kids[ki];	    if (!sub->elems[1]) {		LOG123(("  subtree has only one element!\n", ki));		if (ki > 0 && n->kids[ki-1]->elems[1]) {		    /*		     * Case 3a, left-handed variant. Child ki has		     * only one element, but child ki-1 has two or		     * more. So we need to move a subtree from ki-1		     * to ki.		     * 		     *                . C .                     . B .		     *               /     \     ->            /     \		     * [more] a A b B c   d D e      [more] a A b   c C d D e		     */		    node234 *sib = n->kids[ki-1];		    int lastelem = (sib->elems[2] ? 2 :				    sib->elems[1] ? 1 : 0);		    sub->kids[2] = sub->kids[1];		    sub->counts[2] = sub->counts[1];		    sub->elems[1] = sub->elems[0];		    sub->kids[1] = sub->kids[0];		    sub->counts[1] = sub->counts[0];		    sub->elems[0] = n->elems[ki-1];		    sub->kids[0] = sib->kids[lastelem+1];		    sub->counts[0] = sib->counts[lastelem+1];		    if (sub->kids[0]) sub->kids[0]->parent = sub;		    n->elems[ki-1] = sib->elems[lastelem];		    sib->kids[lastelem+1] = NULL;		    sib->counts[lastelem+1] = 0;		    sib->elems[lastelem] = NULL;		    n->counts[ki] = countnode234(sub);		    LOG123(("  case 3a left\n"));		    LOG123(("  index and left subtree count before adjustment: %d, %d\n",			 index, n->counts[ki-1]));		    index += n->counts[ki-1];		    n->counts[ki-1] = countnode234(sib);		    index -= n->counts[ki-1];		    LOG123(("  index and left subtree count after adjustment: %d, %d\n",			 index, n->counts[ki-1]));		} else if (ki < 3 && n->kids[ki+1] &&			   n->kids[ki+1]->elems[1]) {		    /*		     * Case 3a, right-handed variant. ki has only		     * one element but ki+1 has two or more. Move a		     * subtree from ki+1 to ki.		     * 		     *      . B .                             . C .		     *     /     \                ->         /     \		     *  a A b   c C d D e [more]      a A b B c   d D e [more]		     */		    node234 *sib = n->kids[ki+1];		    int j;		    sub->elems[1] = n->elems[ki];		    sub->kids[2] = sib->kids[0];		    sub->counts[2] = sib->counts[0];		    if (sub->kids[2]) sub->kids[2]->parent = sub;		    n->elems[ki] = sib->elems[0];		    sib->kids[0] = sib->kids[1];		    sib->counts[0] = sib->counts[1];		    for (j = 0; j < 2 && sib->elems[j+1]; j++) {			sib->kids[j+1] = sib->kids[j+2];			sib->counts[j+1] = sib->counts[j+2];			sib->elems[j] = sib->elems[j+1];		    }		    sib->kids[j+1] = NULL;		    sib->counts[j+1] = 0;		    sib->elems[j] = NULL;		    n->counts[ki] = countnode234(sub);		    n->counts[ki+1] = countnode234(sib);		    LOG123(("  case 3a right\n"));		} else {		    /*		     * Case 3b. ki has only one element, and has no		     * neighbor with more than one. So pick a		     * neighbor and merge it with ki, taking an		     * element down from n to go in the middle.		     *		     *      . B .                .		     *     /     \     ->        |		     *  a A b   c C d      a A b B c C d		     * 		     * (Since at all points we have avoided		     * descending to a node with only one element,		     * we can be sure that n is not reduced to		     * nothingness by this move, _unless_ it was		     * the very first node, ie the root of the		     * tree. In that case we remove the now-empty		     * root and replace it with its single large		     * child as shown.)		     */		    node234 *sib;		    int j;		    if (ki > 0) {			ki--;			index += n->counts[ki] + 1;		    }		    sib = n->kids[ki];		    sub = n->kids[ki+1];		    sub->kids[3] = sub->kids[1];		    sub->counts[3] = sub->counts[1];		    sub->elems[2] = sub->elems[0];		    sub->kids[2] = sub->kids[0];		    sub->counts[2] = sub->counts[0];		    sub->elems[1] = n->elems[ki];		    sub->kids[1] = sib->kids[1];		    sub->counts[1] = sib->counts[1];		    if (sub->kids[1]) sub->kids[1]->parent = sub;		    sub->elems[0] = sib->elems[0];		    sub->kids[0] = sib->kids[0];		    sub->counts[0] = sib->counts[0];		    if (sub->kids[0]) sub->kids[0]->parent = sub;		    n->counts[ki+1] = countnode234(sub);		    sfree(sib);		    /*		     * That's built the big node in sub. Now we		     * need to remove the reference to sib in n.		     */		    for (j = ki; j < 3 && n->kids[j+1]; j++) {			n->kids[j] = n->kids[j+1];			n->counts[j] = n->counts[j+1];			n->elems[j] = j<2 ? n->elems[j+1] : NULL;		    }		    n->kids[j] = NULL;		    n->counts[j] = 0;		    if (j < 3) n->elems[j] = NULL;		    LOG123(("  case 3b ki=%d\n", ki));		    if (!n->elems[0]) {			/*			 * The root is empty and needs to be			 * removed.			 */			LOG123(("  shifting root!\n"));			t->root = sub;			sub->parent = NULL;			sfree(n);		    }		}	    }	    n = sub;	}	if (!retval)	    retval = n->elems[ei];	if (ei==-1)	    return NULL;	       /* although this shouldn't happen */	/*	 * Treat special case: this is the one remaining item in	 * the tree. n is the tree root (no parent), has one	 * element (no elems[1]), and has no kids (no kids[0]).	 */	if (!n->parent && !n->elems[1] && !n->kids[0]) {	    LOG123(("  removed last element in tree\n"));	    sfree(n);	    t->root = NULL;	    return retval;	}	/*	 * Now we have the element we want, as n->elems[ei], and we	 * have also arranged for that element not to be the only	 * one in its node. So...	 */	if (!n->kids[0] && n->elems[1]) {	    /*	     * Case 1. n is a leaf node with more than one element,	     * so it's _really easy_. Just delete the thing and	     * we're done.	     */	    int i;	    LOG123(("  case 1\n"));	    for (i = ei; i < 2 && n->elems[i+1]; i++)		n->elems[i] = n->elems[i+1];	    n->elems[i] = NULL;	    /*	     * Having done that to the leaf node, we now go back up	     * the tree fixing the counts.	     */	    while (n->parent) {		int childnum;		childnum = (n->parent->kids[0] == n ? 0 :			    n->parent->kids[1] == n ? 1 :			    n->parent->kids[2] == n ? 2 : 3);		n->parent->counts[childnum]--;		n = n->parent;	    }	    return retval;	       /* finished! */	} else if (n->kids[ei]->elems[1]) {	    /*	     * Case 2a. n is an internal node, and the root of the	     * subtree to the left of e has more than one element.	     * So find the predecessor p to e (ie the largest node	     * in that subtree), place it where e currently is, and	     * then start the deletion process over again on the	     * subtree with p as target.	     */	    node234 *m = n->kids[ei];	    void *target;	    LOG123(("  case 2a\n"));	    while (m->kids[0]) {		m = (m->kids[3] ? m->kids[3] :		     m->kids[2] ? m->kids[2] :		     m->kids[1] ? m->kids[1] : m->kids[0]);		     	    }	    target = (m->elems[2] ? m->elems[2] :		      m->elems[1] ? m->elems[1] : m->elems[0]);	    n->elems[ei] = target;	    index = n->counts[ei]-1;	    n = n->kids[ei];	} else if (n->kids[ei+1]->elems[1]) {	    /*	     * Case 2b, symmetric to 2a but s/left/right/ and	     * s/predecessor/successor/. (And s/largest/smallest/).	     */	    node234 *m = n->kids[ei+1];	    void *target;	    LOG123(("  case 2b\n"));	    while (m->kids[0]) {		m = m->kids[0];	    }	    target = m->elems[0];	    n->elems[ei] = target;	    n = n->kids[ei+1];	    index = 0;	} else {	    /*	     * Case 2c. n is an internal node, and the subtrees to	     * the left and right of e both have only one element.	     * So combine the two subnodes into a single big node	     * with their own elements on the left and right and e	     * in the middle, then restart the deletion process on	     * that subtree, with e still as target.	     */	    node234 *a = n->kids[ei], *b = n->kids[ei+1];	    int j;	    LOG123(("  case 2c\n"));	    a->elems[1] = n->elems[ei];	    a->kids[2] = b->kids[0];	    a->counts[2] = b->counts[0];	    if (a->kids[2]) a->kids[2]->parent = a;	    a->elems[2] = b->elems[0];	    a->kids[3] = b->kids[1];	    a->counts[3] = b->counts[1];	    if (a->kids[3]) a->kids[3]->parent = a;	    sfree(b);	    n->counts[ei] = countnode234(a);	    /*	     * That's built the big node in a, and destroyed b. Now	     * remove the reference to b (and e) in n.	     */	    for (j = ei; j < 2 && n->elems[j+1]; j++) {		n->elems[j] = n->elems[j+1];		n->kids[j+1] = n->kids[j+2];		n->counts[j+1] = n->counts[j+2];	    }	    n->elems[j] = NULL;	    n->kids[j+1] = NULL;	    n->counts[j+1] = 0;            /*             * It's possible, in this case, that we've just removed             * the only element in the root of the tree. If so,             * shift the root.             */            if (n->elems[0] == NULL) {                LOG123(("  shifting root!\n"));                t->root = a;                a->parent = NULL;                sfree(n);            }	    /*	     * Now go round the deletion process again, with n	     * pointing at the new big node and e still the same.	     */	    n = a;	    index = a->counts[0] + a->counts[1] + 1;	}    }}void *delpos234(tree234 *t, int index) {    if (index < 0 || index >= countnode234(t->root))	return NULL;    return delpos234_internal(t, index);}void *del234(tree234 *t, void *e) {    int index;    if (!findrelpos234(t, e, NULL, REL234_EQ, &index))		return NULL;		       /* it wasn't in there anyway */    return delpos234_internal(t, index); /* it's there; delete it. */}#ifdef TEST/* * Test code for the 2-3-4 tree. This code maintains an alternative * representation of the data in the tree, in an array (using the * obvious and slow insert and delete functions). After each tree * operation, the verify() function is called, which ensures all * the tree properties are preserved: *  - node->child->parent always equals node *  - tree->root->parent always equals NULL

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -