Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何生成最大不平衡AVL树_C_Algorithm_Data Structures_Tree_Avl Tree - Fatal编程技术网

C 如何生成最大不平衡AVL树

C 如何生成最大不平衡AVL树,c,algorithm,data-structures,tree,avl-tree,C,Algorithm,Data Structures,Tree,Avl Tree,我写了一封信。出于测试目的,我想有一种方法来填充一棵树,使其最大程度地不平衡,即,使其具有其包含的节点数的最大高度 AVL树有一个很好的特性,即如果从空树开始,按升序(或降序)插入节点,则树始终是完全平衡的(即,对于给定数量的节点,它有其最小高度)。从空树T0开始,为每个节点n生成精确平衡的AVL树Tn的一个整数键序列是简单的 k1=0 kn+1=kn+1,即kn=n-1 我正在寻找一个(希望是简单的)整数键序列,当插入到最初的空树T0中时,生成的AVL树T0,…,Tn都是最大不平衡的 我还

我写了一封信。出于测试目的,我想有一种方法来填充一棵树,使其最大程度地不平衡,即,使其具有其包含的节点数的最大高度

AVL树有一个很好的特性,即如果从空树开始,按升序(或降序)插入节点,则树始终是完全平衡的(即,对于给定数量的节点,它有其最小高度)。从空树T0开始,为每个节点n生成精确平衡的AVL树Tn的一个整数键序列是简单的

  • k1=0
  • kn+1=kn+1,即kn=n-1
我正在寻找一个(希望是简单的)整数键序列,当插入到最初的空树T0中时,生成的AVL树T0,…,Tn都是最大不平衡的

我还对只有最后一棵树Tn最大不平衡的解决方案感兴趣(节点数n将是算法的一个参数)

满足约束的解

  • 最大(k1,…,kn)-最小(k1,…,kn)+1≤ 2N
是首选,但不是严格要求。4 n而不是2 n的关键范围可能是一个合理的目标

我在互联网上找不到任何关于通过插入生成最大高度的AVL树的信息。当然,我要寻找的生成树序列将包括所有所谓的Fibonacci树,它们是给定深度的AVL树,节点数最少。有趣的是,英文维基百科在关于AVL树的文章中甚至没有提到斐波那契树(也没有斐波那契数!),而德国维基百科有一个非常好的完全致力于它们的文章。但我对我的问题仍然一无所知


C语言的位旋转黑客是受欢迎的。

我已经找到了我的问题的答案,但我仍然希望能找到一种更简单,尤其是更省时,而不是更少节省空间的算法,希望它也具有更好的键范围属性

其思想是生成给定高度(必须事先知道)的斐波那契树,完全避免所有树的旋转。中间树通过选择插入顺序保持AVL平衡。因为它们的高度与它们连接的两棵斐波那契树中较低的树相同,所以它们都是最大不平衡的

插入是通过虚拟插入Fibonacci树序列中的所有节点来完成的,但是,对于每个虚拟树,有效地只插入高度为1的子树节点。这些是两个连续斐波那契树之间的“增量”节点

以下是它在最大高度为5的情况下的工作原理:

insert 0
=> Fibonacci tree of height 1 (1 node):
                0
insert 8
=> Fibonacci tree of height 2 (2 nodes):
                0
                        8
insert -8
insert 12
=> Fibonacci tree of height 3 (4 nodes):
                0
       -8               8
                           12
insert -4
insert 4
insert 14
=> Fibonacci tree of height 4 (7 nodes):
                0
       -8               8
           -4       4      12
                             14
insert -12
insert -2
insert 6
insert 10
insert 15
=> Fibonacci tree of height 5 (12 nodes):
                0
       -8               8
  -12      -4       4      12
             -2       6  10  14
                              15
下面是代码(简化):

这是最接近我的版本中的代码(这里有一个静态
fibs
数组):

static int fibs[]={0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,28872747,9227465,14930352,24157817,39088169,63245986,334151155,1655801414141417943797,49037;
void fibonacci_子树(int根、int高度、int*fib)
{
如果(高度==1){
将_插入_树(根);
}否则,如果(高度==2){
将_插入_树(root+*fib);
}否则,如果(高度>=3){
斐波那契子树(根-*fib,高度-2,fib-2);
斐波那契子树(根+*fib,高度-1,fib-1);
}
}
...

对于(高度=1;高度基本溶液

斐波那契树有几个属性可用于形成紧凑的斐波那契树:

static int fibs[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170};

void fibonacci_subtree(int root, int height, int *fib)
{
    if (height == 1) {
        insert_into_tree(root);
    } else if (height == 2) {
        insert_into_tree(root + *fib);
    } else if (height >= 3) {
        fibonacci_subtree(root - *fib, height - 2, fib - 2);
        fibonacci_subtree(root + *fib, height - 1, fib - 1);
    }
}

...

for (height = 1; height <= max_height; height++) {
    fibonacci_subtree(0, height, fibs + max_height - 1);
}
  • 斐波那契树中的每个节点本身就是斐波那契树
  • 高度为n的斐波那契树中的节点数等于Fn+2-1
  • 节点及其左子节点之间的节点数等于节点左子节点的右子节点中的节点数
  • 节点及其右子节点之间的节点数等于节点的右子节点的左子节点中的节点数
  • 在不丧失一般性的情况下,我们假设我们的斐波那契树具有以下附加属性:

  • 如果节点的高度为n,则左侧子节点的高度为n-2,右侧子节点的高度为n-1
  • 结合这些属性,我们发现高度为n的节点与其左右子节点之间的节点数等于Fn-1-1,我们可以利用这一事实生成一个紧凑的斐波那契树:

    static int fibs[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170};
    
    void fibonacci_subtree(int root, int height, int *fib)
    {
        if (height == 1) {
            insert_into_tree(root);
        } else if (height == 2) {
            insert_into_tree(root + *fib);
        } else if (height >= 3) {
            fibonacci_subtree(root - *fib, height - 2, fib - 2);
            fibonacci_subtree(root + *fib, height - 1, fib - 1);
        }
    }
    
    ...
    
    for (height = 1; height <= max_height; height++) {
        fibonacci_subtree(0, height, fibs + max_height - 1);
    }
    
    可以使用此闭合形式解决方案,使用两个嵌套循环来解决问题:

    // Used by the outer loop to calculate the first key of the inner loop
    int outerNodeKey = 0;
    int *outerFib = fibs + max_height - 1;
    
    for(int height = 1; height <= max_height; height++) {
    
        int innerNodeKey = outerNodeKey;
        int *smallFib = fibs + max_height - height + 3; // Hat tip: @WalterTross
    
        for(int n = fibs[height] - 1; n >= 0; n--) {
            insert_into_tree(innerNodeKey);
    
            // Use closed-form expression to pick between two elements of the Fibonacci sequence
            bool smallSkip = 2 + floor(n * phi) - floor((n + 1) * phi);
            innerNodeKey += smallSkip ? *smallFib : *(smallFib + 1);
        }
    
        if(height & 0x1) {
            // When height is odd, add *outerFib.
            outerNodeKey += *outerFib;
        } else {
            // Otherwise, backtrack and reduce the gap for next time.
            outerNodeKey -= (*outerFib) << 1;
            outerFib -= 2;
        }
    }
    
    //外部循环用于计算内部循环的第一个键
    int outerNodeKey=0;
    int*outerFib=fibs+最大高度-1;
    对于(整数高度=1;高度=0;n--){
    将_插入_树(innerNodeKey);
    //使用闭式表达式在斐波那契序列的两个元素之间进行选择
    bool smallSkip=2+楼层(n*phi)-楼层(n+1)*phi);
    innerNodeKey+=smallSkip?*smallFib:*(smallFib+1);
    }
    if(高度&0x1){
    //当高度为奇数时,添加*outerFib。
    outerNodeKey+=*outerFib;
    }否则{
    //否则,回溯并缩小差距,以备下次使用。
    
    outerNodeKey-=(*outerFib)有趣的问题。看起来您已经有了一个很好的解决方案,但我会发现一个更简单的组合方法

    假设:

    • 设U(n)表示高度为n的最大不平衡AVL树中的节点数

    • U(0)=0

    • U(1)=1

    • U(n)=U(n-1)+U(n-2)+1表示n>=2(即,一个根节点加上两个最大不平衡的子树)

    • 为了方便起见,我们假设U(n-1)总是左子树,U(n-2)总是右子树

    • 让每个节点由一个表示路径的唯一字符串表示
      static int fibs[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170};
      
      void fibonacci_subtree(int root, int height, int *fib)
      {
          if (height == 1) {
              insert_into_tree(root);
          } else if (height == 2) {
              insert_into_tree(root + *fib);
          } else if (height >= 3) {
              fibonacci_subtree(root - *fib, height - 2, fib - 2);
              fibonacci_subtree(root + *fib, height - 1, fib - 1);
          }
      }
      
      ...
      
      for (height = 1; height <= max_height; height++) {
          fibonacci_subtree(0, height, fibs + max_height - 1);
      }
      
      void fibonacci_subtree(int root, int height, int *fib, int num_gaps, bool prune_gaps)
      {
          if(height < 1)
              return;
          if(prune_gaps && height <= 2) {
              if(!num_gaps) {
                  if(height == 1) {
                      insert_into_tree(root);
                  } else if(height == 2) {
                      insert_into_tree(root + *fib);
                  }
              }
              return;
          }
          if(height == 1) {
              insert_into_tree(root);
          } else {
              int max_rr_gaps = *(fib - 1);
              int rr_gaps = num_gaps > max_rr_gaps ? max_rr_gaps : num_gaps;
              num_gaps -= rr_gaps;
      
              int max_rl_gaps = *(fib - 2);
              int rl_gaps = num_gaps > max_rl_gaps ? max_rl_gaps : num_gaps;
              num_gaps -= rl_gaps;
      
              int lr_gaps = num_gaps > max_rl_gaps ? max_rl_gaps : num_gaps;
              num_gaps -= lr_gaps;
      
              int ll_gaps = num_gaps;
              fibonacci_subtree(root - *fib + lr_gaps, height - 2, fib - 2, lr_gaps + ll_gaps, prune_gaps);
              fibonacci_subtree(root + *fib - rl_gaps, height - 1, fib - 1, rr_gaps + rl_gaps, prune_gaps);
          }
      }
      
      void compact_fill(int min_key, int max_key)
      {
          int num_nodes = max_key - min_key + 1;
          int *fib = fibs;
          int max_height = 0;
      
          while(num_nodes > *(fib + 2) - 1) {
              max_height++;
              fib++;
          }
      
          int num_gaps = *(fib + 2) - 1 - num_nodes;
      
          int natural_max = *(fib + 1) - 1;
          int max_r_gaps = *(fib - 1);
          int r_gaps = num_gaps > max_r_gaps ? max_r_gaps : num_gaps;
          natural_max -= r_gaps;
      
          int root_offset = max_key - natural_max;
      
          for (int height = 1; height <= max_height; height++) {
              fibonacci_subtree(root_offset, height, fibs + max_height - 1, num_gaps, height == max_height);
          }
      }
      
      static double phi = (1.0 + sqrt(5.0)) / 2.0;
      
      bool fibWord(int n)
      {
          return 2 + floor(n * phi) - floor((n + 1) * phi);
      }
      
      // Used by the outer loop to calculate the first key of the inner loop
      int outerNodeKey = 0;
      int *outerFib = fibs + max_height - 1;
      
      for(int height = 1; height <= max_height; height++) {
      
          int innerNodeKey = outerNodeKey;
          int *smallFib = fibs + max_height - height + 3; // Hat tip: @WalterTross
      
          for(int n = fibs[height] - 1; n >= 0; n--) {
              insert_into_tree(innerNodeKey);
      
              // Use closed-form expression to pick between two elements of the Fibonacci sequence
              bool smallSkip = 2 + floor(n * phi) - floor((n + 1) * phi);
              innerNodeKey += smallSkip ? *smallFib : *(smallFib + 1);
          }
      
          if(height & 0x1) {
              // When height is odd, add *outerFib.
              outerNodeKey += *outerFib;
          } else {
              // Otherwise, backtrack and reduce the gap for next time.
              outerNodeKey -= (*outerFib) << 1;
              outerFib -= 2;
          }
      }
      
      void GeneratePaths(int height, int level)
      {
        int rLimit = height - level - 1;
        GeneratePaths(height, rLimit, level, string.Empty, 0);
      }
      
      void GeneratePaths(int height, int rLimit, int level, string prefix, int prefixlen)
      {
        if (prefixlen + 1 < level)
        {
          GeneratePaths(height, rLimit, level, prefix + "L", prefixlen + 1);
          if (rLimit > 0)
              GeneratePaths(height, rLimit - 1, level, prefix + "R", prefixlen + 1);
        }
        else if (prefixlen + 1 == level)
        {
          InsertNode(prefix + "L", height)
          if (rLimit > 0)
              InsertNode(prefix + "R", height);
        }
      }
      
      void InsertNode(string path, int height)
      {
        int key = fibonacci(height);
        int index = height - 2;
      
        for (int i=0; i < path.length(), i++)
        {
          int difference = fibonacci(index);
          char c = path.charAt(i);
          if (c == 'L')
          {
            key -= difference;
            index -= 1;
          }
          else if (c == 'R')
          {
            key += difference;
            index -= 2;
          }
        }
      
        InsertKey(key);
      }
      
                  5
            3           7
         2     4      6   8
        1 3   4      6
       1