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

📄 tree234.c

📁 NullSofts criptable install system2.28源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
        sib->counts[i + 1] = 0;
      }
    }
    if (lparent)
    {
      lparent->kids[pki] = n;
      lparent->counts[pki] = lcount;
      n->parent = lparent;
      rparent->kids[0] = sib;
      rparent->counts[0] = rcount;
      sib->parent = rparent;
    } else
    {
      halves[0] = n;
      n->parent = NULL;
      halves[1] = sib;
      sib->parent = NULL;
    }
    lparent = n;
    rparent = sib;
    pki = ki;
    LOG(("  left node %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(("  right node %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n",
         sib, sib->kids[0], sib->counts[0], sib->elems[0], sib->kids[1],
         sib->counts[1], sib->elems[1], sib->kids[2], sib->counts[2],
         sib->elems[2], sib->kids[3], sib->counts[3]));

    n = sub;
  }

  /*
   * We've come off the bottom here, so we've successfully split
   * the tree into two equally high subtrees. The only problem is
   * that some of the nodes down the fault line will be smaller
   * than the minimum permitted size. (Since this is a 2-3-4
   * tree, that means they'll be zero-element one-child nodes.)
   */
  LOG(("  fell off bottom, lroot is %p, rroot is %p\n",
       halves[0], halves[1]));
  lparent->counts[pki] = rparent->counts[0] = 0;
  lparent->kids[pki] = rparent->kids[0] = NULL;

  /*
   * So now we go back down the tree from each of the two roots,
   * fixing up undersize nodes.
   */
  for (half = 0; half < 2; half++)
  {
    /*
     * Remove the root if it's undersize (it will contain only
     * one child pointer, so just throw it away and replace it
     * with its child). This might happen several times.
     */
    while (halves[half] && !halves[half]->elems[0])
    {
      LOG(("  root %p is undersize, throwing away\n", halves[half]));
      halves[half] = halves[half]->kids[0];
      sfree(halves[half]->parent);
      halves[half]->parent = NULL;
      LOG(("  new root is %p\n", halves[half]));
    }

    n = halves[half];
    while (n)
    {
      void (*toward) (node234 * n, int ki, int *k, int *index);
      int ni, merge;

      /*
       * Now we have a potentially undersize node on the
       * right (if half==0) or left (if half==1). Sort it
       * out, by merging with a neighbour or by transferring
       * subtrees over. At this time we must also ensure that
       * nodes are bigger than minimum, in case we need an
       * element to merge two nodes below.
       */
      LOG(("  node %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]));
      if (half == 1)
      {
        ki = 0;                 /* the kid we're interested in */
        ni = 1;                 /* the neighbour */
        merge = 0;              /* for merge: leftmost of the two */
        toward = trans234_subtree_left;
      } else
      {
        ki = (n->kids[3] ? 3 : n->kids[2] ? 2 : 1);
        ni = ki - 1;
        merge = ni;
        toward = trans234_subtree_right;
      }

      sub = n->kids[ki];
      if (sub && !sub->elems[1])
      {
        /*
         * This node is undersized or minimum-size. If we
         * can merge it with its neighbour, we do so;
         * otherwise we must be able to transfer subtrees
         * over to it until it is greater than minimum
         * size.
         */
        int undersized = (!sub->elems[0]);
        LOG(("  child %d is %ssize\n", ki,
             undersized ? "under" : "minimum-"));
        LOG(("  neighbour is %s\n",
             n->kids[ni]->elems[2] ? "large" :
             n->kids[ni]->elems[1] ? "medium" : "small"));
        if (!n->kids[ni]->elems[1] ||
            (undersized && !n->kids[ni]->elems[2]))
        {
          /*
           * Neighbour is small, or possibly neighbour is
           * medium and we are undersize.
           */
          trans234_subtree_merge(n, merge, NULL, NULL);
          sub = n->kids[merge];
          if (!n->elems[0])
          {
            /*
             * n is empty, and hence must have been the
             * root and needs to be removed.
             */
            assert(!n->parent);
            LOG(("  shifting root!\n"));
            halves[half] = sub;
            halves[half]->parent = NULL;
            sfree(n);
          }
        } else
        {
          /* Neighbour is big enough to move trees over. */
          toward(n, ni, NULL, NULL);
          if (undersized)
            toward(n, ni, NULL, NULL);
        }
      }
      n = sub;
    }
  }

  t->root = halves[1];
  return halves[0];
}

tree234 *splitpos234(tree234 * t, int index, int before)
{
  tree234 *ret;
  node234 *n;
  int count;

  count = countnode234(t->root);
  if (index < 0 || index > count)
    return NULL;                /* error */
  ret = newtree234(t->cmp);
  n = split234_internal(t, index);
  if (before)
  {
    /* We want to return the ones before the index. */
    ret->root = n;
  } else
  {
    /*
     * We want to keep the ones before the index and return the
     * ones after.
     */
    ret->root = t->root;
    t->root = n;
  }
  return ret;
}

tree234 *split234(tree234 * t, void *e, cmpfn234 cmp, int rel)
{
  int before;
  int index;

  assert(rel != REL234_EQ);

  if (rel == REL234_GT || rel == REL234_GE)
  {
    before = 1;
    rel = (rel == REL234_GT ? REL234_LE : REL234_LT);
  } else
  {
    before = 0;
  }
  if (!findrelpos234(t, e, cmp, rel, &index))
    index = 0;

  return splitpos234(t, index + 1, before);
}

static node234 *copynode234(node234 * n, copyfn234 copyfn,
                            void *copyfnstate)
{
  int i;
  node234 *n2 = mknew(node234);

  for (i = 0; i < 3; i++)
  {
    if (n->elems[i] && copyfn)
      n2->elems[i] = copyfn(copyfnstate, n->elems[i]);
    else
      n2->elems[i] = n->elems[i];
  }

  for (i = 0; i < 4; i++)
  {
    if (n->kids[i])
    {
      n2->kids[i] = copynode234(n->kids[i], copyfn, copyfnstate);
      n2->kids[i]->parent = n2;
    } else
    {
      n2->kids[i] = NULL;
    }
    n2->counts[i] = n->counts[i];
  }

  return n2;
}

tree234 *copytree234(tree234 * t, copyfn234 copyfn, void *copyfnstate)
{
  tree234 *t2;

  t2 = newtree234(t->cmp);
  t2->root = copynode234(t->root, copyfn, copyfnstate);
  t2->root->parent = NULL;

  return t2;
}

#ifdef TEST

/*
 * Test code for the 2-3-4 tree. This code maintains an alternative
 * representation of the data in the tree, in an array (using the
 * obvious and slow insert and delete functions). After each tree
 * operation, the verify() function is called, which ensures all
 * the tree properties are preserved:
 *  - node->child->parent always equals node
 *  - tree->root->parent always equals NULL
 *  - number of kids == 0 or number of elements + 1;
 *  - tree has the same depth everywhere
 *  - every node has at least one element
 *  - subtree element counts are accurate
 *  - any NULL kid pointer is accompanied by a zero count
 *  - in a sorted tree: ordering property between elements of a
 *    node and elements of its children is preserved
 * and also ensures the list represented by the tree is the same
 * list it should be. (This last check also doubly verifies the
 * ordering properties, because the `same list it should be' is by
 * definition correctly ordered. It also ensures all nodes are
 * distinct, because the enum functions would get caught in a loop
 * if not.)
 */

#include <stdarg.h>

#define srealloc realloc

/*
 * Error reporting function.
 */
void error(char *fmt, ...)
{
  va_list ap;
  printf("ERROR: ");
  va_start(ap, fmt);
  vfprintf(stdout, fmt, ap);
  va_end(ap);
  printf("\n");
}

/* The array representation of the data. */
void **array;
int arraylen, arraysize;
cmpfn234 cmp;

/* The tree representation of the same data. */
tree234 *tree;

/*
 * Routines to provide a diagnostic printout of a tree. Currently
 * relies on every element in the tree being a one-character string
 * :-)
 */
typedef struct {
  char **levels;
} dispctx;

int dispnode(node234 * n, int level, dispctx * ctx)
{
  if (level == 0)
  {
    int xpos = strlen(ctx->levels[0]);
    int len;

    if (n->elems[2])
      len = sprintf(ctx->levels[0] + xpos, " %s%s%s",
                    n->elems[0], n->elems[1], n->elems[2]);
    else if (n->elems[1])
      len = sprintf(ctx->levels[0] + xpos, " %s%s",
                    n->elems[0], n->elems[1]);
    else
      len = sprintf(ctx->levels[0] + xpos, " %s", n->elems[0]);
    return xpos + 1 + (len - 1) / 2;
  } else
  {
    int xpos[4], nkids;
    int nodelen, mypos, myleft, x, i;

    xpos[0] = dispnode(n->kids[0], level - 3, ctx);
    xpos[1] = dispnode(n->kids[1], level - 3, ctx);
    nkids = 2;
    if (n->kids[2])
    {
      xpos[2] = dispnode(n->kids[2], level - 3, ctx);
      nkids = 3;
    }
    if (n->kids[3])
    {
      xpos[3] = dispnode(n->kids[3], level - 3, ctx);
      nkids = 4;
    }

    if (nkids == 4)
      mypos = (xpos[1] + xpos[2]) / 2;
    else if (nkids == 3)
      mypos = xpos[1];
    else
      mypos = (xpos[0] + xpos[1]) / 2;
    nodelen = nkids * 2 - 1;
    myleft = mypos - ((nodelen - 1) / 2);
    assert(myleft >= xpos[0]);
    assert(myleft + nodelen - 1 <= xpos[nkids - 1]);

    x = strlen(ctx->levels[level]);
    while (x <= xpos[0] && x < myleft)
      ctx->levels[level][x++] = ' ';
    while (x < myleft)
      ctx->levels[level][x++] = '_';
    if (nkids == 4)
      x += sprintf(ctx->levels[level] + x, ".%s.%s.%s.",
                   n->elems[0], n->elems[1], n->elems[2]);
    else if (nkids == 3)
      x += sprintf(ctx->levels[level] + x, ".%s.%s.",
                   n->elems[0], n->elems[1]);
    else
      x += sprintf(ctx->levels[level] + x, ".%s.", n->elems[0]);
    while (x < xpos[nkids - 1])
      ctx->levels[level][x++] = '_';
    ctx->levels[level][x] = '\0';

    x = strlen(ctx->levels[level - 1]);
    for (i = 0; i < nkids; i++)
    {
      int rpos, pos;
      rpos = xpos[i];
      if (i > 0 && i < nkids - 1)
        pos = myleft + 2 * i;
      else
        pos = rpos;
      if (rpos < pos)
        rpos++;
      while (x < pos && x < rpos)
        ctx->levels[level - 1][x++] = ' ';
      if (x == pos)
        ctx->levels[level - 1][x++] = '|';
      while (x < pos || x < rpos)
        ctx->levels[level - 1][x++] = '_';
      if (x == pos)
        ctx->levels[level - 1][x++] = '|';
    }
    ctx->levels[level - 1][x] = '\0';

    x = strlen(ctx->levels[level - 2]);
    for (i = 0; i < nkids; i++)
    {
      int rpos = xpos[i];

      while (x < rpos)
        ctx->levels[level - 2][x++] = ' ';
      ctx->levels[level - 2][x++] = '|';
    }
    ctx->levels[level - 2][x] = '\0';

    return mypos;
  }
}

void disptree(tree234 * t)
{
  dispctx ctx;
  char *leveldata;
  int width = count234(t);
  int ht = height234(t) * 3 - 2;
  int i;

  if (!t->root)
  {
    printf("[empty tree]\n");
  }

  leveldata = smalloc(ht * (width + 2));
  ctx.levels = smalloc(ht * sizeof(char *));
  for (i = 0; i < ht; i++)
  {
    ctx.levels[i] = leveldata + i * (width + 2);
    ctx.levels[i][0] = '\0';
  }

  (void) dispnode(t->root, ht - 1, &ctx);

  for (i = ht; i--;)
    printf("%s\n", ctx.levels[i]);

  sfree(ctx.levels);
  sfree(leveldata);
}

typedef struct {
  int treedepth;
  int elemcount;
} chkctx;

int
chknode(chkctx * ctx, int level, node234 * node,
        void *lowbound, void *highbound)
{
  int nkids, nelems;
  int i;
  int count;

  /* Count the non-NULL kids. */
  for (nkids = 0; nkids < 4 && node->kids[nkids]; nkids++);
  /* Ensure no kids beyond the first NULL are non-NULL. */
  for (i = nkids; i < 4; i++)
    if (node->kids[i])
    {
      error("node %p: nkids=%d but kids[%d] non-NULL", node, nkids, i);
    } else if (node->counts[i])
    {
      error("node %p: kids[%d] NULL but count[%d]=%d nonzero",
            node, i, i, node->counts[i]);
    }

  /* Count the non-NULL elements. */
  for (nelems = 0; nelems < 3 && node->elems[nelems]; nelems++);
  /* Ensure no elements beyond the first NULL are non-NULL. */
  for (i = nelems; i < 3; i++)
    if (node->elems[i])
    {
      error("node %p: nelems=%d but elems[%d] non-NULL", node, nelems, i);
    }

  if (nkids == 0)
  {
    /*
     * If nkids==0, this is a leaf node; verify that the tree

⌨️ 快捷键说明

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