Example #1
0
/**
 * Find datum in search tree. KEY is the key to be located, rootp is the
 * address of tree root, cmpfun the ordering function.
 */
GtKeytype gt_rbt_find(const GtKeytype key,
                      const GtRBTnode *root,
                      GtDictcomparefunction cmpfun,
                      void *cmpinfo)
{
  if (root == NULL)
  {
    return GtKeytypeerror;
  }
  CHECK_TREE (root);
  while (root != NULL)
  {
    int r;

    r = cmpfun (key, root->key, cmpinfo);
    if (r == 0)
    {
      return root->key;
    }
    if (r < 0)
    {
      root = root->left;
    }
    else
    {
      root = root->right;
    }
  }
  return GtKeytypeerror;
}
Example #2
0
/* Find datum in search tree.
   KEY is the key to be located, ROOTP is the address of tree root,
   COMPAR the ordering function.  */
void *
__tfind (const void *key,
     void *const *vrootp,
     __compar_fn_t compar)
{
  node *rootp = (node *) vrootp;

  if (rootp == NULL)
    return NULL;

  CHECK_TREE (*rootp);

  while (*rootp != NULL)
    {
      node root = *rootp;
      int r;

      r = (*compar) (key, root->key);
      if (r == 0)
	return root;

      rootp = r < 0 ? &root->left : &root->right;
    }
  return NULL;
}
Example #3
0
/* Find datum in search tree.
   KEY is the key to be located, ROOTP is the address of tree root,
   COMPAR the ordering function.  */
void *
__tfind (const void *key, void *const *vrootp, __compar_fn_t compar)
{
  node root;
  node *rootp = (node *) vrootp;

  if (rootp == NULL)
    return NULL;

  root = DEREFNODEPTR(rootp);
  CHECK_TREE (root);

  while (DEREFNODEPTR(rootp) != NULL)
    {
      root = DEREFNODEPTR(rootp);
      int r;

      r = (*compar) (key, root->key);
      if (r == 0)
	return root;

      rootp = r < 0 ? LEFTPTR(root) : RIGHTPTR(root);
    }
  return NULL;
}
Example #4
0
/* Find or insert datum into search tree.
   KEY is the key to be located, ROOTP is the address of tree root,
   COMPAR the ordering function.  */
void *
__tsearch (const void *key, void **vrootp, __compar_fn_t compar)
{
  node q;
  node *parentp = NULL, *gparentp = NULL;
  node *rootp = (node *) vrootp;
  node *nextp;
  int r = 0, p_r = 0, gp_r = 0; /* No they might not, Mr Compiler.  */

  if (rootp == NULL)
    return NULL;

  /* This saves some additional tests below.  */
  if (*rootp != NULL)
    (*rootp)->red = 0;

  CHECK_TREE (*rootp);

  nextp = rootp;
  while (*nextp != NULL)
    {
      node root = *rootp;
      r = (*compar) (key, root->key);
      if (r == 0)
	return root;

      maybe_split_for_insert (rootp, parentp, gparentp, p_r, gp_r, 0);
      /* If that did any rotations, parentp and gparentp are now garbage.
	 That doesn't matter, because the values they contain are never
	 used again in that case.  */

      nextp = r < 0 ? &root->left : &root->right;
      if (*nextp == NULL)
	break;

      gparentp = parentp;
      parentp = rootp;
      rootp = nextp;

      gp_r = p_r;
      p_r = r;
    }

  q = (struct node_t *) malloc (sizeof (struct node_t));
  if (q != NULL)
    {
      *nextp = q;			/* link new node to old */
      q->key = key;			/* initialize new node */
      q->red = 1;
      q->left = q->right = NULL;

      if (nextp != rootp)
	/* There may be two red edges in a row now, which we must avoid by
	   rotating the tree.  */
	maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1);
    }

  return q;
}
Example #5
0
void
__tdestroy (void *vroot, __free_fn_t freefct)
{
  node root = (node) vroot;

  CHECK_TREE (root);

  if (root != NULL)
    tdestroy_recurse (root, freefct);
}
Example #6
0
/* Walk the nodes of a tree.
   ROOT is the root of the tree to be walked, ACTION the function to be
   called at each node.  */
void
__twalk (const void *vroot, __action_fn_t action)
{
  const_node root = (const_node) vroot;

  CHECK_TREE (root);

  if (root != NULL && action != NULL)
    trecurse (root, action, 0);
}
Example #7
0
void
__tdestroy (void *vroot, void (*freefct)(void *))
{
  node root = (node) vroot;

  CHECK_TREE (root);

  if (root != NULL)
    tdestroy_recurse (root, freefct);
}
Example #8
0
int gt_rbt_walkwithstop (const GtRBTnode *root, GtDictaction action,
                         void *actinfo)
{
  CHECK_TREE(root);
  if (root != NULL && action != NULL)
  {
    int retcode = mytreerecursewithstop (root, action, 0, actinfo);
    RBT_CHECK_RETURN_CODE;
  }
  return 0;
}
Example #9
0
void gt_rbt_destroy(bool dofreekey,
                    GtFreekeyfunction freekey,
                    void *freeinfo,
                    GtRBTnode *root)
{
  CHECK_TREE(root);
  if (root != NULL)
  {
    redblacktreedestroyrecurse (dofreekey, freekey, freeinfo, root);
  }
}
Example #10
0
int gt_rbt_walk (const GtRBTnode *root,GtDictaction action,void *actinfo)
{
  CHECK_TREE(root);
  if (root != NULL && action != NULL)
  {
    if (mytreerecurse (root, action, 0, actinfo) != 0)
    {
      return -1;
    }
  }
  return 0;
}
Example #11
0
int gt_rbt_walkrange(const GtRBTnode *root,
                     GtDictaction action,
                     void *actinfo,
                     GtComparewithkey greaterequalleft,
                     GtComparewithkey lowerequalright,
                     void *cmpinfo)
{
  CHECK_TREE(root);
  if (root != NULL && action != NULL)
  {
    if (rangetreerecurse (root, action, 0, actinfo, greaterequalleft,
                          lowerequalright, cmpinfo) != 0)
    {
      return -1;
    }
  }
  return 0;
}
Example #12
0
/* Delete node with given key.
   KEY is the key to be deleted, ROOTP is the address of the root of tree,
   COMPAR the comparison function.  */
void *
__tdelete (const void *key, void **vrootp, __compar_fn_t compar)
{
  node p, q, r, retval;
  int cmp;
  node *rootp = (node *) vrootp;
  node root, unchained;
  /* Stack of nodes so we remember the parents without recursion.  It's
     _very_ unlikely that there are paths longer than 40 nodes.  The tree
     would need to have around 250.000 nodes.  */
  int stacksize = 40;
  int sp = 0;
  node **nodestack = alloca (sizeof (node *) * stacksize);

  if (rootp == NULL)
    return NULL;
  p = *rootp;
  if (p == NULL)
    return NULL;

  CHECK_TREE (p);

  while ((cmp = (*compar) (key, (*rootp)->key)) != 0)
    {
      if (sp == stacksize)
	{
	  node **newstack;
	  stacksize += 20;
	  newstack = alloca (sizeof (node *) * stacksize);
	  nodestack = memcpy (newstack, nodestack, sp * sizeof (node *));
	}

      nodestack[sp++] = rootp;
      p = *rootp;
      rootp = ((cmp < 0)
	       ? &(*rootp)->left
	       : &(*rootp)->right);
      if (*rootp == NULL)
	return NULL;
    }

  /* This is bogus if the node to be deleted is the root... this routine
     really should return an integer with 0 for success, -1 for failure
     and errno = ESRCH or something.  */
  retval = p;

  /* We don't unchain the node we want to delete. Instead, we overwrite
     it with its successor and unchain the successor.  If there is no
     successor, we really unchain the node to be deleted.  */

  root = *rootp;

  r = root->right;
  q = root->left;

  if (q == NULL || r == NULL)
    unchained = root;
  else
    {
      node *parent = rootp, *up = &root->right;
      for (;;)
	{
	  if (sp == stacksize)
	    {
	      node **newstack;
	      stacksize += 20;
	      newstack = alloca (sizeof (node *) * stacksize);
	      nodestack = memcpy (newstack, nodestack, sp * sizeof (node *));
	    }
	  nodestack[sp++] = parent;
	  parent = up;
	  if ((*up)->left == NULL)
	    break;
	  up = &(*up)->left;
	}
      unchained = *up;
    }

  /* We know that either the left or right successor of UNCHAINED is NULL.
     R becomes the other one, it is chained into the parent of UNCHAINED.  */
  r = unchained->left;
  if (r == NULL)
    r = unchained->right;
  if (sp == 0)
    *rootp = r;
  else
    {
      q = *nodestack[sp-1];
      if (unchained == q->right)
	q->right = r;
      else
	q->left = r;
    }

  if (unchained != root)
    root->key = unchained->key;
  if (!unchained->red)
    {
      /* Now we lost a black edge, which means that the number of black
	 edges on every path is no longer constant.  We must balance the
	 tree.  */
      /* NODESTACK now contains all parents of R.  R is likely to be NULL
	 in the first iteration.  */
      /* NULL nodes are considered black throughout - this is necessary for
	 correctness.  */
      while (sp > 0 && (r == NULL || !r->red))
	{
	  node *pp = nodestack[sp - 1];
	  p = *pp;
	  /* Two symmetric cases.  */
	  if (r == p->left)
	    {
	      /* Q is R's brother, P is R's parent.  The subtree with root
		 R has one black edge less than the subtree with root Q.  */
	      q = p->right;
	      if (q->red)
		{
		  /* If Q is red, we know that P is black. We rotate P left
		     so that Q becomes the top node in the tree, with P below
		     it.  P is colored red, Q is colored black.
		     This action does not change the black edge count for any
		     leaf in the tree, but we will be able to recognize one
		     of the following situations, which all require that Q
		     is black.  */
		  q->red = 0;
		  p->red = 1;
		  /* Left rotate p.  */
		  p->right = q->left;
		  q->left = p;
		  *pp = q;
		  /* Make sure pp is right if the case below tries to use
		     it.  */
		  nodestack[sp++] = pp = &q->left;
		  q = p->right;
		}
	      /* We know that Q can't be NULL here.  We also know that Q is
		 black.  */
	      if ((q->left == NULL || !q->left->red)
		  && (q->right == NULL || !q->right->red))
		{
		  /* Q has two black successors.  We can simply color Q red.
		     The whole subtree with root P is now missing one black
		     edge.  Note that this action can temporarily make the
		     tree invalid (if P is red).  But we will exit the loop
		     in that case and set P black, which both makes the tree
		     valid and also makes the black edge count come out
		     right.  If P is black, we are at least one step closer
		     to the root and we'll try again the next iteration.  */
		  q->red = 1;
		  r = p;
		}
	      else
		{
		  /* Q is black, one of Q's successors is red.  We can
		     repair the tree with one operation and will exit the
		     loop afterwards.  */
		  if (q->right == NULL || !q->right->red)
		    {
		      /* The left one is red.  We perform the same action as
			 in maybe_split_for_insert where two red edges are
			 adjacent but point in different directions:
			 Q's left successor (let's call it Q2) becomes the
			 top of the subtree we are looking at, its parent (Q)
			 and grandparent (P) become its successors. The former
			 successors of Q2 are placed below P and Q.
			 P becomes black, and Q2 gets the color that P had.
			 This changes the black edge count only for node R and
			 its successors.  */
		      node q2 = q->left;
		      q2->red = p->red;
		      p->right = q2->left;
		      q->left = q2->right;
		      q2->right = q;
		      q2->left = p;
		      *pp = q2;
		      p->red = 0;
		    }
		  else
		    {
		      /* It's the right one.  Rotate P left. P becomes black,
			 and Q gets the color that P had.  Q's right successor
			 also becomes black.  This changes the black edge
			 count only for node R and its successors.  */
		      q->red = p->red;
		      p->red = 0;

		      q->right->red = 0;

		      /* left rotate p */
		      p->right = q->left;
		      q->left = p;
		      *pp = q;
		    }

		  /* We're done.  */
		  sp = 1;
		  r = NULL;
		}
	    }
	  else
	    {
	      /* Comments: see above.  */
	      q = p->left;
	      if (q->red)
		{
		  q->red = 0;
		  p->red = 1;
		  p->left = q->right;
		  q->right = p;
		  *pp = q;
		  nodestack[sp++] = pp = &q->right;
		  q = p->left;
		}
	      if ((q->right == NULL || !q->right->red)
		       && (q->left == NULL || !q->left->red))
		{
		  q->red = 1;
		  r = p;
		}
	      else
		{
		  if (q->left == NULL || !q->left->red)
		    {
		      node q2 = q->right;
		      q2->red = p->red;
		      p->left = q2->right;
		      q->right = q2->left;
		      q2->left = q;
		      q2->right = p;
		      *pp = q2;
		      p->red = 0;
		    }
		  else
		    {
		      q->red = p->red;
		      p->red = 0;
		      q->left->red = 0;
		      p->left = q->right;
		      q->right = p;
		      *pp = q;
		    }
		  sp = 1;
		  r = NULL;
		}
	    }
	  --sp;
	}
      if (r != NULL)
	r->red = 0;
    }

  free (unchained);
  return retval;
}
Example #13
0
/**
 * Delete node with given key. rootp is the
 * address of the root of tree, cmpfun the comparison function.
 */
int gt_rbt_delete(const GtKeytype key,
                  GtRBTnode **rootp,
                  GtDictcomparefunction cmpfun,
                  void *cmpinfo)
{
  GtRBTnode *p,
          *q,
          *r,
          *root,
          *unchained,
          ***nodestack,
          **staticstack[STATICSTACKSPACE];
  size_t allocsize;
  int cmp;
  unsigned long stacksize = STATICSTACKSPACE,
                nextfreestack = 0;

  p = *rootp;
  if (p == NULL)
  {
    return -1;
  }
  CHECK_TREE(p);
  nodestack = &staticstack[0];
  while ((cmp = cmpfun (key, (*rootp)->key, cmpinfo)) != 0)
  {
    CHECKNODESTACKSPACE;
    nodestack[nextfreestack++] = rootp;
    p = *rootp;
    if (cmp < 0)
    {
      rootp = &(*rootp)->left;
    }
    else
    {
      rootp = &(*rootp)->right;
    }
    if (*rootp == NULL)
    {
      DELETENODESTACKSPACE;
      return -1;
    }
  }

  /*
     We don't unchain the node we want to delete.
     Instead, we overwrite it with
     its successor and unchain the successor.  If there is no successor, we
     really unchain the node to be deleted.
   */

  root = *rootp;

  r = root->right;
  q = root->left;

  if (q == NULL || r == NULL)
  {
    unchained = root;
  }
  else
  {
    GtRBTnode **parent = rootp,
      **up = &root->right;

    for (;;)
    {
      CHECKNODESTACKSPACE;
      nodestack[nextfreestack++] = parent;
      parent = up;
      if ((*up)->left == NULL)
      {
        break;
      }
      up = &(*up)->left;
    }
    unchained = *up;
  }

  /*
   * We know that either the left or right successor of UNCHAINED is NULL. R
   * becomes the other one, it is chained into the parent of UNCHAINED.
   */
  r = unchained->left;
  if (r == NULL)
  {
    r = unchained->right;
  }
  if (nextfreestack == 0)
  {
    *rootp = r;
  }
  else
  {
    q = *nodestack[nextfreestack - 1];
    if (unchained == q->right)
    {
      q->right = r;
    }
    else
    {
      q->left = r;
    }
  }

  if (unchained != root)
  {
    root->key = unchained->key;
  }
  if (!unchained->red)
  {
    /*
       Now we lost a black edge, which means that the number of
       black edges on every path is no longer constant.
       We must balance the tree.

       NODESTACK now contains all parents of R.
       R is likely to be NULL in the
       first iteration.

       NULL nodes are considered black throughout - this is necessary for
       correctness.
     */
    while (nextfreestack > 0 && (r == NULL || !r->red))
    {
      GtRBTnode **pp = nodestack[nextfreestack - 1];

      p = *pp;
      /*
         Two symmetric cases.
       */
      if (r == p->left)
      {
        /*
         * Q is R's brother, P is R's parent.  The subtree with root R has one
         * black edge less than the subtree with root Q.
         */
        q = p->right;
        if (q != NULL && q->red)
        {
          /*
           * If Q is red, we know that P is black. We rotate P left so that Q
           * becomes the top node in the tree, with P below it.  P is colored
           * red, Q is colored black. This action does not change the black
           * edge count for any leaf in the tree, but we will be able to
           * recognize one of the following situations, which all require that
           * Q is black.
           */
          q->red = false;
          p->red = true;
          /*
             Left rotate p.
           */
          p->right = q->left;
          q->left = p;
          *pp = q;
          /*
           * Make sure pp is right if the case below tries to use it.
           */
          CHECKNODESTACKSPACE;         /* this has been added by S.K. */
          nodestack[nextfreestack++] = pp = &q->left;
          q = p->right;
        }
        gt_assert(q != NULL);
        /*
         * We know that Q can't be NULL here.  We also know that Q is black.
         */
        if ((q->left == NULL || !q->left->red)
            && (q->right == NULL || !q->right->red))
        {
          /*
           * Q has two black successors.  We can simply color Q red. The whole
           * subtree with root P is now missing one black edge. Note that this
           * action can temporarily make the tree invalid (if P is red).  But
           * we will exit the loop in that case and set P black, which both
           * makes the tree valid and also makes the black edge count come out
           * right.  If P is black, we are at least one step closer to the root
           * and we'll try again the next iteration.
           */
          q->red = true;
          r = p;
        }
        else
        {
          /*
           * Q is black, one of Q's successors is red.  We can repair the tree
           * with one operation and will exit the loop afterwards.
           */
          if (q->right == NULL || !q->right->red)
          {
            /*
             * The left one is red.  We perform the same action as in
             * maybe_split_for_insert where two red edges are adjacent but
             * point in different directions: Q's left successor (let's call it
             * Q2) becomes the top of the subtree we are looking at, its parent
             * (Q) and grandparent (P) become its successors. The former
             * successors of Q2 are placed below P and Q. P becomes black, and
             * Q2 gets the color that P had. This changes the black edge count
             * only for node R and its successors.
             */
            GtRBTnode *q2 = q->left;

            q2->red = p->red;
            p->right = q2->left;

            q->left = q2->right;
            q2->right = q;
            q2->left = p;
            *pp = q2;
            p->red = false;
          }
          else
          {
            /*
             * It's the right one.  Rotate P left. P becomes black, and Q gets
             * the color that P had.  Q's right successor also becomes black.
             * This changes the black edge count only for node R and its
             * successors.
             */
            q->red = p->red;
            p->red = false;

            q->right->red = false;

            /*
               left rotate p
             */
            p->right = q->left;
            q->left = p;
            *pp = q;
          }

          /*
             We're done.
           */
          nextfreestack = 1UL;
          r = NULL;
        }
      }
      else
      {
        /*
           Comments: see above.
         */
        q = p->left;
        if (q != NULL && q->red)
        {
          q->red = false;
          p->red = true;
          p->left = q->right;
          q->right = p;
          *pp = q;
          CHECKNODESTACKSPACE;         /* this has been added by S.K. */
          nodestack[nextfreestack++] = pp = &q->right;
          q = p->left;
        }
        gt_assert(q != NULL);
        if ((q->right == NULL || !q->right->red)
            && (q->left == NULL || !q->left->red))
        {
          q->red = true;
          r = p;
        }
        else
        {
          if (q->left == NULL || !q->left->red)
          {
            GtRBTnode *q2 = q->right;

            q2->red = p->red;
            p->left = q2->right;
            q->right = q2->left;
            q2->left = q;
            q2->right = p;
            *pp = q2;
            p->red = false;
          }
          else
          {
            q->red = p->red;
            p->red = false;
            q->left->red = false;
            p->left = q->right;
            q->right = p;
            *pp = q;
          }
          nextfreestack = 1UL;
          r = NULL;
        }
      }
      --nextfreestack;
    }
    if (r != NULL)
    {
      r->red = false;
    }
  }
  gt_free (unchained);
  DELETENODESTACKSPACE;
  return 0;
}
Example #14
0
/**
 * Find or insert datum with given key into search tree. rootp
 * is the address of tree root, cmpfun the ordering function.
 */
GtKeytype gt_rbt_search(const GtKeytype key,
                        bool *nodecreated,
                        GtRBTnode **rootp,
                        GtDictcomparefunction cmpfun,
                        void *cmpinfo)
{
  GtRBTnode *newnode,
          **parentp = NULL,
          **gparentp = NULL,
          **nextp;
          int r = 0,
              p_r = 0,
              gp_r = 0;   /* No they might not, Mr Compiler. */

  if (rootp == NULL)
  {
    *nodecreated = false;
    return GtKeytypeerror;
  }

  /*
     This saves some additional tests below.
   */
  if (*rootp != NULL)
  {
    (*rootp)->red = false;
  }
  CHECK_TREE (*rootp);
  nextp = rootp;
  while (*nextp != NULL)
  {
    GtRBTnode *root = *rootp;

    r = cmpfun (key, root->key, cmpinfo);
    if (r == 0)
    {
      *nodecreated = false;
      return root->key;
    }

    maybe_split_for_insert (rootp, parentp, gparentp, p_r, gp_r, 0);
    /*
     * If that did any rotations, parentp and gparentp are now garbage. That
     * doesn't matter, because the values they contain are never used again in
     * that case.
     */

    nextp = r < 0 ? &root->left : &root->right;
    if (*nextp == NULL)
    {
      break;
    }

    gparentp = parentp;
    parentp = rootp;
    rootp = nextp;

    gp_r = p_r;
    p_r = r;
  }

  newnode = (GtRBTnode *) gt_malloc (sizeof (GtRBTnode));
  *nextp = newnode;                    /* link new node to old */
  newnode->key = key;                  /* initialize new node */
  newnode->red = true;
  newnode->left = NULL;
  newnode->right = NULL;
  if (nextp != rootp)
  {
    /*
       There may be two red edges in a row now, which we must
       avoid by rotating the tree.
     */
    maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1UL);
  }
  *nodecreated = true;
  return newnode->key;
}
Example #15
0
/* Find or insert datum into search tree.
   KEY is the key to be located, ROOTP is the address of tree root,
   COMPAR the ordering function.  */
void *
__tsearch (const void *key, void **vrootp, __compar_fn_t compar)
{
  node q, root;
  node *parentp = NULL, *gparentp = NULL;
  node *rootp = (node *) vrootp;
  node *nextp;
  int r = 0, p_r = 0, gp_r = 0; /* No they might not, Mr Compiler.  */

#ifdef USE_MALLOC_LOW_BIT
  static_assert (alignof (max_align_t) > 1, "malloc must return aligned ptrs");
#endif

  if (rootp == NULL)
    return NULL;

  /* This saves some additional tests below.  */
  root = DEREFNODEPTR(rootp);
  if (root != NULL)
    SETBLACK(root);

  CHECK_TREE (root);

  nextp = rootp;
  while (DEREFNODEPTR(nextp) != NULL)
    {
      root = DEREFNODEPTR(rootp);
      r = (*compar) (key, root->key);
      if (r == 0)
	return root;

      maybe_split_for_insert (rootp, parentp, gparentp, p_r, gp_r, 0);
      /* If that did any rotations, parentp and gparentp are now garbage.
	 That doesn't matter, because the values they contain are never
	 used again in that case.  */

      nextp = r < 0 ? LEFTPTR(root) : RIGHTPTR(root);
      if (DEREFNODEPTR(nextp) == NULL)
	break;

      gparentp = parentp;
      parentp = rootp;
      rootp = nextp;

      gp_r = p_r;
      p_r = r;
    }

  q = (struct node_t *) malloc (sizeof (struct node_t));
  if (q != NULL)
    {
      /* Make sure the malloc implementation returns naturally aligned
	 memory blocks when expected.  Or at least even pointers, so we
	 can use the low bit as red/black flag.  Even though we have a
	 static_assert to make sure alignof (max_align_t) > 1 there could
	 be an interposed malloc implementation that might cause havoc by
	 not obeying the malloc contract.  */
#ifdef USE_MALLOC_LOW_BIT
      assert (((uintptr_t) q & (uintptr_t) 0x1) == 0);
#endif
      SETNODEPTR(nextp,q);		/* link new node to old */
      q->key = key;			/* initialize new node */
      SETRED(q);
      SETLEFT(q,NULL);
      SETRIGHT(q,NULL);

      if (nextp != rootp)
	/* There may be two red edges in a row now, which we must avoid by
	   rotating the tree.  */
	maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1);
    }

  return q;
}