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

📄 tree234.c

📁 NullSofts criptable install system2.28源代码
💻 C
📖 第 1 页 / 共 5 页
字号:

  assert(!left->elems[2] && !right->elems[2]);  /* neither is large! */
  lsize = (left->elems[1] ? 2 : left->elems[0] ? 1 : 0);
  rsize = (right->elems[1] ? 2 : right->elems[0] ? 1 : 0);

  left->elems[lsize] = n->elems[ki];

  for (i = 0; i < rsize + 1; i++)
  {
    left->kids[lsize + 1 + i] = right->kids[i];
    left->counts[lsize + 1 + i] = right->counts[i];
    if (left->kids[lsize + 1 + i])
      left->kids[lsize + 1 + i]->parent = left;
    if (i < rsize)
      left->elems[lsize + 1 + i] = right->elems[i];
  }

  n->counts[ki] += rightlen + 1;

  sfree(right);

  /*
   * Move the rest of n up by one.
   */
  for (i = ki + 1; i < 3; i++)
  {
    n->kids[i] = n->kids[i + 1];
    n->counts[i] = n->counts[i + 1];
  }
  for (i = ki; i < 2; i++)
  {
    n->elems[i] = n->elems[i + 1];
  }
  n->kids[3] = NULL;
  n->counts[3] = 0;
  n->elems[2] = NULL;

  if (k)
  {
    LOG(("    before: k,index = %d,%d\n", (*k), (*index)));
    if ((*k) == ki + 1)
    {
      (*k)--;
      (*index) += leftlen + 1;
    } else if ((*k) > ki + 1)
    {
      (*k)--;
    }
    LOG(("    after: k,index = %d,%d\n", (*k), (*index)));
  }

  LOG(("    parent %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%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]));
  LOG(("    merged %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n",
       left,
       left->kids[0], left->counts[0], left->elems[0],
       left->kids[1], left->counts[1], left->elems[1],
       left->kids[2], left->counts[2], left->elems[2],
       left->kids[3], left->counts[3]));

}

/*
 * 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 ki, i;

  retval = NULL;

  n = t->root;                  /* by assumption this is non-NULL */
  LOG(("deleting item %d from tree %p\n", index, t));
  while (1)
  {
    node234 *sub;

    LOG(("  node %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %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 <= n->counts[1])
    {
      ki = 1;
    } else if (index -= n->counts[1] + 1, index <= n->counts[2])
    {
      ki = 2;
    } else if (index -= n->counts[2] + 1, index <= n->counts[3])
    {
      ki = 3;
    } else
    {
      assert(0);                /* can't happen */
    }

    if (!n->kids[0])
      break;                    /* n is a leaf node; we're here! */

    /*
     * Check to see if we've found our target element. If so,
     * we must choose a new target (we'll use the old target's
     * successor, which will be in a leaf), move it into the
     * place of the old one, continue down to the leaf and
     * delete the old copy of the new target.
     */
    if (index == n->counts[ki])
    {
      node234 *m;
      LOG(("  found element in internal node, index %d\n", ki));
      assert(n->elems[ki]);     /* must be a kid _before_ an element */
      ki++;
      index = 0;
      for (m = n->kids[ki]; m->kids[0]; m = m->kids[0])
        continue;
      LOG(("  replacing with element \"%s\" from leaf node %p\n",
           m->elems[0], m));
      retval = n->elems[ki - 1];
      n->elems[ki - 1] = m->elems[0];
    }

    /*
     * Recurse down to subtree ki. If it has only one element,
     * we have to do some transformation to start with.
     */
    LOG(("  moving to subtree %d\n", ki));
    sub = n->kids[ki];
    if (!sub->elems[1])
    {
      LOG(("  subtree has only one element!\n"));
      if (ki > 0 && n->kids[ki - 1]->elems[1])
      {
        /*
         * 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.
         */
        trans234_subtree_right(n, ki - 1, &ki, &index);
      } else if (ki < 3 && n->kids[ki + 1] && n->kids[ki + 1]->elems[1])
      {
        /*
         * Child ki has only one element, but ki+1 has
         * two or more. Move a subtree from ki+1 to ki.
         */
        trans234_subtree_left(n, ki + 1, &ki, &index);
      } else
      {
        /*
         * ki is small with only small neighbours. Pick a
         * neighbour and merge with it.
         */
        trans234_subtree_merge(n, ki > 0 ? ki - 1 : ki, &ki, &index);
        sub = n->kids[ki];

        if (!n->elems[0])
        {
          /*
           * The root is empty and needs to be
           * removed.
           */
          LOG(("  shifting root!\n"));
          t->root = sub;
          sub->parent = NULL;
          sfree(n);
          n = NULL;
        }
      }
    }

    if (n)
      n->counts[ki]--;
    n = sub;
  }

  /*
   * Now n is a leaf node, and ki marks the element number we
   * want to delete. We've already arranged for the leaf to be
   * bigger than minimum size, so let's just go to it.
   */
  assert(!n->kids[0]);
  if (!retval)
    retval = n->elems[ki];

  for (i = ki; i < 2 && n->elems[i + 1]; i++)
    n->elems[i] = n->elems[i + 1];
  n->elems[i] = NULL;

  /*
   * It's just possible that we have reduced the leaf to zero
   * size. This can only happen if it was the root - so destroy
   * it and make the tree empty.
   */
  if (!n->elems[0])
  {
    LOG(("  removed last element in tree, destroying empty root\n"));
    assert(n == t->root);
    sfree(n);
    t->root = NULL;
  }

  return retval;                /* finished! */
}

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. */
}

/*
 * Join two subtrees together with a separator element between
 * them, given their relative height.
 * 
 * (Height<0 means the left tree is shorter, >0 means the right
 * tree is shorter, =0 means (duh) they're equal.)
 * 
 * It is assumed that any checks needed on the ordering criterion
 * have _already_ been done.
 * 
 * The value returned in `height' is 0 or 1 depending on whether the
 * resulting tree is the same height as the original larger one, or
 * one higher.
 */
static node234 *join234_internal(node234 * left, void *sep,
                                 node234 * right, int *height)
{
  node234 *root, *node;
  int relht = *height;
  int ki;

  LOG(("  join: joining %p \"%s\" %p, relative height is %d\n",
       left, sep, right, relht));
  if (relht == 0)
  {
    /*
     * The trees are the same height. Create a new one-element
     * root containing the separator and pointers to the two
     * nodes.
     */
    node234 *newroot;
    newroot = mknew(node234);
    newroot->kids[0] = left;
    newroot->counts[0] = countnode234(left);
    newroot->elems[0] = sep;
    newroot->kids[1] = right;
    newroot->counts[1] = countnode234(right);
    newroot->elems[1] = NULL;
    newroot->kids[2] = NULL;
    newroot->counts[2] = 0;
    newroot->elems[2] = NULL;
    newroot->kids[3] = NULL;
    newroot->counts[3] = 0;
    newroot->parent = NULL;
    if (left)
      left->parent = newroot;
    if (right)
      right->parent = newroot;
    *height = 1;
    LOG(("  join: same height, brand new root\n"));
    return newroot;
  }

  /*
   * This now works like the addition algorithm on the larger
   * tree. We're replacing a single kid pointer with two kid
   * pointers separated by an element; if that causes the node to
   * overload, we split it in two, move a separator element up to
   * the next node, and repeat.
   */
  if (relht < 0)
  {
    /*
     * Left tree is shorter. Search down the right tree to find
     * the pointer we're inserting at.
     */
    node = root = right;
    while (++relht < 0)
    {
      node = node->kids[0];
    }
    ki = 0;
    right = node->kids[ki];
  } else
  {
    /*
     * Right tree is shorter; search down the left to find the
     * pointer we're inserting at.
     */
    node = root = left;
    while (--relht > 0)
    {
      if (node->elems[2])
        node = node->kids[3];
      else if (node->elems[1])
        node = node->kids[2];
      else
        node = node->kids[1];
    }
    if (node->elems[2])
      ki = 3;
    else if (node->elems[1])
      ki = 2;
    else
      ki = 1;
    left = node->kids[ki];
  }

  /*
   * Now proceed as for addition.
   */
  *height = add234_insert(left, sep, right, &root, node, ki);

  return root;
}
static int height234(tree234 * t)
{
  int level = 0;
  node234 *n = t->root;
  while (n)
  {
    level++;
    n = n->kids[0];
  }
  return level;
}

tree234 *join234(tree234 * t1, tree234 * t2)
{
  int size2 = countnode234(t2->root);
  if (size2 > 0)
  {
    void *element;
    int relht;

    if (t1->cmp)
    {
      element = index234(t2, 0);
      element = findrelpos234(t1, element, NULL, REL234_GE, NULL);
      if (element)
        return NULL;
    }

    element = delpos234(t2, 0);
    relht = height234(t1) - height234(t2);
    t1->root = join234_internal(t1->root, element, t2->root, &relht);
    t2->root = NULL;
  }
  return t1;
}

tree234 *join234r(tree234 * t1, tree234 * t2)
{
  int size1 = countnode234(t1->root);
  if (size1 > 0)
  {
    void *element;
    int relht;

    if (t2->cmp)
    {
      element = index234(t1, size1 - 1);
      element = findrelpos234(t2, element, NULL, REL234_LE, NULL);
      if (element)
        return NULL;
    }

    element = delpos234(t1, size1 - 1);
    relht = height234(t1) - height234(t2);
    t2->root = join234_internal(t1->root, element, t2->root, &relht);
    t1->root = NULL;
  }
  return t2;
}

/*
 * Split out the first <index> elements in a tree and return a
 * pointer to the root node. Leave the root node of the remainder
 * in t.
 */
static node234 *split234_internal(tree234 * t, int index)
{
  node234 *halves[2], *n, *sib, *sub;
  node234 *lparent, *rparent;
  int ki, pki=0, i, half, lcount, rcount;

  n = t->root;
  LOG(("splitting tree %p at point %d\n", t, index));

  /*
   * Easy special cases. After this we have also dealt completely
   * with the empty-tree case and we can assume the root exists.
   */
  if (index == 0)               /* return nothing */
    return NULL;
  if (index == countnode234(t->root))
  {                             /* return the whole tree */
    node234 *ret = t->root;
    t->root = NULL;
    return ret;
  }

  /*
   * Search down the tree to find the split point.
   */
  lparent = rparent = NULL;
  while (n)
  {
    LOG(("  node %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %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));
    lcount = index;
    rcount = countnode234(n) - lcount;
    if (index <= n->counts[0])
    {
      ki = 0;
    } else if (index -= n->counts[0] + 1, index <= n->counts[1])
    {
      ki = 1;
    } else if (index -= n->counts[1] + 1, index <= n->counts[2])
    {
      ki = 2;
    } else
    {
      index -= n->counts[2] + 1;
      ki = 3;
    }

    LOG(("  splitting at subtree %d\n", ki));
    sub = n->kids[ki];

    LOG(("  splitting at child index %d\n", ki));

    /*
     * Split the node, put halves[0] on the right of the left
     * one and halves[1] on the left of the right one, put the
     * new node pointers in halves[0] and halves[1], and go up
     * a level.
     */
    sib = mknew(node234);
    for (i = 0; i < 3; i++)
    {
      if (i + ki < 3 && n->elems[i + ki])
      {
        sib->elems[i] = n->elems[i + ki];
        sib->kids[i + 1] = n->kids[i + ki + 1];
        if (sib->kids[i + 1])
          sib->kids[i + 1]->parent = sib;
        sib->counts[i + 1] = n->counts[i + ki + 1];
        n->elems[i + ki] = NULL;
        n->kids[i + ki + 1] = NULL;
        n->counts[i + ki + 1] = 0;
      } else
      {
        sib->elems[i] = NULL;
        sib->kids[i + 1] = NULL;

⌨️ 快捷键说明

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