Ejemplo n.º 1
0
/*  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;
}
Ejemplo n.º 2
0
Archivo: misc.c Proyecto: kazuho/kmyacc
/*
 * 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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
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,
    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;
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
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;
			}
		}
	}
}
Ejemplo n.º 8
0
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);
    }
}
Ejemplo n.º 9
0
int test_call(int a, int b, int compar(int x, int y))
{
	return compar(a, b);
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
/* 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;
}
Ejemplo n.º 12
0
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;
}
Ejemplo n.º 13
0
/* 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;
}
Ejemplo n.º 14
0
/* 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;
}
Ejemplo n.º 15
0
/* 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. */
    }
}