@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\n", 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\n", 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\n" : "no\n"); 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, "\n\t\\tree"); 177 tree_print(root, fd); 178 fprintf(fd, "\n\n"); 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\n", 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\n", 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; }
