zoukankan      html  css  js  c++  java
  • 二叉树的旋转操作和平衡判断

      #返回上一级

    @Author: 张海拔

    @Update: 2014-2-2

    @Link: http://www.cnblogs.com/zhanghaiba/p/3537221.html

    【问题描述】(问题描述摘自“http://ac.jobdu.com/problem.php?pid=1541”,略有修改)

    旋转是二叉树的基本操作,我们可以对任意一个存在父亲节点的子节点进行旋转,包括如下几种形式(设被旋转节点为x,其父亲节点为p):
    1.左旋
    旋转前,x是p的右儿子。
    x的左儿子(若存在)变为p的右儿子,p变为x的左儿子。如下图

    2.右旋
    旋转前,x是p的左儿子。
    x的右儿子(若存在)变为p的左儿子,p变为x的右儿子。如下图

    综上,我们可以通过检查选择前x是p的左儿子还是右儿子来判断该次旋转是左旋还是右旋。
    给定一颗n个节点的二叉树,其节点由1至n编号,并给定一系列操作,如下:
    1.rotate x,对编号x的节点进行旋转,若x为根节点,则不进行任何操作。
    2.parent x,输出编号x的父亲节点编号,若x为根节点输出-1。
    3.size x,输出以x为根节点的子树的节点个数。
    4.balance x,判断以x为根节点的子树是否为平衡树,是则输出"yes",否则输出"no"。


    输入:
    输入包含多组测试用例。
    每组测试用例开头为一个整数n(1<=n<=1000),代表二叉树的节点个数。
    接下去n行描述,二叉树原始的状态,第i行为两个整数x,y,代表i号节点的左儿子节点为x号节点,右儿子节点为y号节点,若x或y为-1,则表示相应儿子节点不存在。编号的范围为1到n。
    接下去一行为一个整数t(1<=t<=50000),代表操作的个数。
    最后t行,每行代表一个对二叉树的操作,描述如上所示。
    输出:
    对于每组测试用例,输出操作parent x,size x和balance x的结果。

    【问题解答】

    一般二叉树的选择分左旋和右旋,左旋的形状是>,右旋的形状是<

    在我看来旋转的对象是最上面的那个节点,为了方便下面描述,形状中的三个节点命名为A、B、C(C可能为空树)。

    1、以左旋为例说明bt_rotate_left():

    (1)旋转即修改孩子指针

    首先,新树根应该是B(new_root),

    然后A(root)的右孩子应该指向B的左孩子(root->right = new_root->left),

    最后“旋转”,A成为B的左孩子(new_root->left = root)。

    经过三步就完成了左旋。

    (2)维护父亲节点信息,对应上述三步修改父亲指针:

    首先新树根B的父亲指向旧树根A的父亲(new_root->par = root-par),

    然后B的左孩子(可能为空)的父亲应该是A(new_root->left->par = root),这里如果没有空节点作为哨兵则需保证new_root->left != NULL,

    最后A的父亲是B,root->par = new_root;

    (3)维护树的节点数,调整选择后的新树根B和旧树根A的size即可。

    新树根的右子树不变,左子树包括原来的左子树,增加的部分是B的右子树和B本身,所以有:

    new_root->size += (root->left->size + 1); 注意没有空节点作为哨兵需保证root->left != NULL

    旧树根的左子树不变,右子树只包括原来的右子树(new_root)的左子树部分,所以有:

    root->size -= (new_root->right->size + 1); 同样要保证root->right != NULL

    2、右旋是完成对称的。

    3、实现的细节包括:

    1)由于需要修改前驱(父亲)节点指针,所以定义一个树根的父亲sentinel,让它的左右孩子都指向树根,

    且判断“父亲的左孩子是否自己”,这样若父亲是sentinel,则一定修改的是左孩子指针。所以打印树时选择bt_show_by_tree(sentinel->left)。

    2)没有空节点哨兵则需要加一些判断防止对空树进行读写parent或size,有空节点哨兵主要注意存储的节点数目很可能翻倍,建树保证翻倍的内存空间。

    下面是代码的完整实现:

      1 /*
      2  *Author: ZhangHaiba
      3  *Date: 2014-2-1
      4  *File: btree_rotate.c
      5  *
      6  *a demo shows how to rotate binary tree while repair link relationship
      7  *and parent, size information.
      8  *
      9  */
     10 
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #define N 1024
     15 #define CMD_LEN 128
     16 
     17 typedef struct btree * btlink;
     18 
     19 typedef struct btree
     20 {
     21     int num;
     22     btlink par;
     23     btlink left;
     24     btlink right;
     25     int size;
     26 }btree;
     27 
     28 //public
     29 btlink NODE(int num, btlink par, btlink left, btlink right, int size);
     30 btlink bt_create(int root_num, btlink par);
     31 btlink bt_left_rotate(btlink root);
     32 btlink bt_right_rotate(btlink root);
     33 void bt_show_by_tree(btlink root);
     34 btlink* bt_search(btlink root, int num);
     35 //private
     36 void tree_print(btlink root, FILE* fd);
     37 
     38 //private for bt_create
     39 int left_num[N]; //the number of left tree root
     40 int right_num[N]; //the number of right tree root
     41 btlink num_map_root[N];
     42 
     43 int main(void)
     44 {
     45     int n, i;
     46 
     47     scanf("%d", &n);
     48     for (i = 1; i <= n; ++i)
     49         scanf("%d%d", left_num+i, right_num+i);
     50     btlink sentinel = NODE(0, sentinel, NULL, NULL, -1);
     51     btlink btree_a = bt_create(1, sentinel);
     52     sentinel->left = sentinel->right = btree_a;
     53     bt_show_by_tree(btree_a);
     54 
     55     int op_times;
     56     char cmd[CMD_LEN];
     57     int root_num;
     58 
     59     scanf("%d", &op_times);
     60     while (op_times--) {
     61         scanf("%s", cmd);
     62         if (strcmp(cmd, "size") == 0) {
     63             scanf("%d", &root_num);
     64             printf("%d
    ", num_map_root[root_num]->size);
     65         } else if (strcmp(cmd, "rotate") == 0) {
     66             scanf("%d", &root_num);
     67             btlink x = num_map_root[root_num];
     68             btlink par = x->par;
     69             if (par == sentinel) //x is root
     70                 continue;
     71             if (par->right == x) {
     72                 if (par->par->left == par) //left first
     73                     par->par->left = bt_left_rotate(par);
     74                 else if (par->par->right == par)
     75                     par->par->right = bt_left_rotate(par);
     76             } else if (par->left == x) {
     77                 if (par->par->left == par) //left first
     78                     par->par->left = bt_right_rotate(par);
     79                 else if (par->par->right == par)
     80                     par->par->right = bt_right_rotate(par);
     81             }
     82             bt_show_by_tree(sentinel->left); //becuase left is first choice
     83         } else if (strcmp(cmd, "parent") == 0) {
     84             scanf("%d", &root_num);
     85             btlink root = num_map_root[root_num];
     86             printf("%d
    ", root->par == sentinel ? -1 : root->par->num);
     87         } else if (strcmp(cmd, "balance") == 0) {
     88             scanf("%d", &root_num);
     89             btlink root = num_map_root[root_num];
     90             int left_size = root->left != NULL ? root->left->size : 0;
     91             int right_size = root->right != NULL ? root->right->size : 0;
     92             printf( abs(left_size - right_size) <= 1 ? "yes
    " : "no
    ");
     93         }
     94     }
     95     return 0;
     96 }
     97 
     98 btlink NODE(int num, btlink par, btlink left, btlink right, int size)
     99 {
    100     btlink born = malloc(sizeof (btree));
    101     born->par = par;
    102     born->num = num;
    103     born->left = left;
    104     born->right = right;
    105     born->size = size;
    106     return born;
    107 }
    108 
    109 btlink bt_create(int num, btlink par) //number begin with 1
    110 {
    111     if (num == -1)
    112         return NULL;
    113     btlink root = NODE(num, par, NULL, NULL, 1);
    114     num_map_root[num] = root;
    115     root->par = par;
    116     root->left = bt_create(left_num[num], root);
    117     root->right = bt_create(right_num[num], root);
    118     if (root->left != NULL && root->right != NULL)
    119         root->size = 1 + root->left->size + root->right->size;
    120     else if (root->left != NULL)
    121         root->size = 1 + root->left->size;
    122     else if (root->right != NULL)
    123         root->size = 1 + root->right->size;
    124     return root;
    125 }
    126 
    127 btlink bt_left_rotate(btlink root)
    128 {
    129     btlink new_root = root->right;
    130     new_root->par = root->par;  //change par
    131     root->right = new_root->left; 
    132     if (new_root->left != NULL)
    133         new_root->left->par = root; //change par
    134     new_root->left = root; 
    135     root->par = new_root;       //change par
    136     //modify size
    137     new_root->size += root->left != NULL ? (root->left->size + 1) : 1;
    138     root->size -= new_root->right != NULL ? (new_root->right->size + 1) : 1;
    139     return new_root;
    140 }
    141 
    142 btlink bt_right_rotate(btlink root)
    143 {
    144     btlink new_root = root->left;
    145     new_root->par = root->par;   //change par
    146     root->left = new_root->right;
    147     if (new_root->right != NULL)
    148         new_root->right->par = root; //change par
    149     new_root->right = root;
    150     root->par = new_root;        //change par
    151     //modify size
    152     new_root->size += root->right != NULL ? (root->right->size + 1) : 1;
    153     root->size -= new_root->left != NULL ? (new_root->left->size + 1) : 1;
    154     return new_root;
    155 }
    156 
    157 void tree_print(btlink root, FILE *fd)
    158 {    
    159     fprintf(fd, "(");
    160     if (root != NULL) {
    161         fprintf(fd, "%d", root->num);
    162         tree_print(root->left, fd);
    163         tree_print(root->right, fd);
    164     }
    165     fprintf(fd, ")");
    166 }
    167 
    168 void bt_show_by_tree(btlink root)
    169 {
    170     char cmd[CMD_LEN];
    171 
    172     sprintf(cmd, "rm -f ./tree_src.txt");
    173     system(cmd);
    174 
    175     FILE *fd = fopen("./tree_src.txt", "a+");
    176     fprintf(fd, "
    	\tree");
    177     tree_print(root, fd);
    178     fprintf(fd, "
    
    ");
    179     fclose(fd);
    180 
    181     sprintf(cmd, "cat ./tree_src.txt | ~/tree/tree");
    182     system(cmd);
    183 }

    测试示范:

    ZhangHaiba-MacBook-Pro:code apple$ ./a.out
    8
    2 3
    4 -1
    -1 6
    -1 5
    -1 -1
    7 8
    -1 -1
    -1 -1
    
                  1
              ____|____
              |       |
              2       3
             _|__   __|__
             |  |   |   |
             4          6
            _|__     ___|___
            |  |     |     |
               5     7     8
              _|__  _|__  _|__
              |  |  |  |  |  |
    
    15
    size 1
    8
    parent 3
    1
    rotate 3
    
                   3
               ____|____
               |       |
               1       6
              _|__  ___|___
              |  |  |     |
              2     7     8
             _|__  _|__  _|__
             |  |  |  |  |  |
             4
            _|__
            |  |
               5
              _|__
              |  |
    
    size 1
    4
    size 3
    8
    parent 3
    -1
    parent 1
    3
    rotate 6
    
                     6
                  ___|____
                  |      |
                  3      8
               ___|___  _|__
               |     |  |  |
               1     7
              _|__  _|__
              |  |  |  |
              2
             _|__
             |  |
             4
            _|__
            |  |
               5
              _|__
              |  |
    
    balance 4
    yes
    balance 1
    no
    size 3
    6
    rotate 1
    
                    6
                 ___|____
                 |      |
                 1      8
              ___|___  _|__
              |     |  |  |
              2     3
             _|__  _|__
             |  |  |  |
             4        7
            _|__     _|__
            |  |     |  |
               5
              _|__
              |  |
    
    balance 1
    yes
    size 3
    2
    parent 3
    1
    ZhangHaiba-MacBook-Pro:code apple$ 

    最后附带jiudu OJ 1541(http://ac.jobdu.com/problem.php?pid=1541)的AC代码:

    这里使用了空树作为哨兵,减少一些rotate操作中的判断次数。

    /*
     *Author: ZhangHaiba
     *Date: 2014-2-1
     *File: jdoj1541_btree_rotate2.c
     *
     *an AC code for jiudu oj problem 1541
     *use null nodes for sentinel 
     */
    
    #include <stdio.h>
    #include <string.h>
    #define N 2048 //be care of null nodes
    #define CMD_LEN 128
    
    typedef struct btree * btlink;
    typedef struct btree
    {
        int num;
        btlink par;
        btlink left;
        btlink right;
        int size;
    }btree;
    
    //public
    btlink NODE(int num, btlink par, btlink left, btlink right, int size);
    btlink bt_create(int root_num, btlink par);
    btlink bt_left_rotate(btlink root);
    btlink bt_right_rotate(btlink root);
    
    //private for bt_create
    int left_num[N]; //the number of left tree root
    int right_num[N]; //the number of right tree root
    btlink num_map_root[N];
    
    //alloc static
    btree memory[N];
    int cnt = 0;
    
    int main(void)
    {
        int n, i, j;
    
        while (scanf("%d", &n) != EOF) {
            cnt = 0; //for memory
            for (i = 1; i <= n; ++i)
                scanf("%d%d", left_num+i, right_num+i);
            btlink sentinel = NODE(0, sentinel, NULL, NULL, -1);
            btlink btree_a = bt_create(1, sentinel);
            sentinel->left = sentinel->right = btree_a;
            int op_times;
            char cmd[CMD_LEN];
            int root_num;
            scanf("%d", &op_times);
            for (j = 0; j < op_times; ++j) {
                scanf("%s", cmd);
                if (strcmp(cmd, "size") == 0) {
                    scanf("%d", &root_num);
                    printf("%d
    ", num_map_root[root_num]->size);
                } else if (strcmp(cmd, "rotate") == 0) {
                    scanf("%d", &root_num);
                    btlink x = num_map_root[root_num];
                    btlink par = x->par;
                    if (par == sentinel)
                        continue;
                    if (par->right == x) {
                        if (par->par->left == par)
                            par->par->left = bt_left_rotate(par);
                        else if (par->par->right == par)
                            par->par->right = bt_left_rotate(par);
                    } else if (par->left == x) {
                        if (par->par->left == par)
                            par->par->left = bt_right_rotate(par);
                        else if (par->par->right == par)
                            par->par->right = bt_right_rotate(par);
                    }
                } else if (strcmp(cmd, "parent") == 0) {
                    scanf("%d", &root_num);
                    btlink root = num_map_root[root_num];
                    printf("%d
    ", root->par == sentinel ? -1 : root->par->num);
            }//while(op_times--)
        }
        return 0;
    }
    
    btlink NODE(int num, btlink par, btlink left, btlink right, int size)
    {
        btlink born = &memory[cnt++];
        born->par = par;
        born->num = num;
        born->left = left;
        born->right = right;
        born->size = size;
        return born;
    }
    
    btlink bt_create(int num, btlink par) //number begin with 1
    {
        if (num == -1)
            return NODE(-1, par, NULL, NULL, 0); //null tree as sentinel end size is 0
        btlink root = NODE(num, par, NULL, NULL, 1);
        num_map_root[num] = root;
        root->par = par;
        root->left = bt_create(left_num[num], root);
        root->right = bt_create(right_num[num], root);
        if (root->left != NULL && root->right != NULL)
            root->size = 1 + root->left->size + root->right->size;
        else if (root->left != NULL)
            root->size = 1 + root->left->size;
        else if (root->right != NULL)
            root->size = 1 + root->right->size;
        return root;
    }
    
    btlink bt_left_rotate(btlink root)
    {
        btlink new_root = root->right;
        new_root->par = root->par; //change par
        root->right = new_root->left; 
        new_root->left->par = root; //change par
        new_root->left = root; 
        root->par = new_root; //change par
    
        new_root->size += (root->left->size + 1);
        root->size -= (new_root->right->size + 1);
    
        return new_root;
    }
    
    btlink bt_right_rotate(btlink root)
    {
        btlink new_root = root->left;
        new_root->par = root->par; //change par
        root->left = new_root->right;
        new_root->right->par = root; //change par
        new_root->right = root;
        root->par = new_root; //change par
    
        new_root->size += (root->right->size + 1);
        root->size -= (new_root->left->size + 1);
    
        return new_root;
    }

      #返回上一级

  • 相关阅读:
    WPF XAML之bing使用StringFormat
    C#程序以管理员权限运行
    注册表REG文件编写大全
    linux 的基本操作(编写shell 脚本)
    linux的基本操作(正则表达式)
    linux的基本操作(shell 脚本的基础知识)
    linux的基本操作(RPM包或者安装源码包)
    linux的基本操作(文件压缩与打包)
    linux的基本操作(文本编辑工具vim)
    linux的基本操作(磁盘管理)
  • 原文地址:https://www.cnblogs.com/zhanghaiba/p/3537221.html
Copyright © 2011-2022 走看看