1066. Root of AVL Tree (25)
时间限制100 ms
内存限制65536 kB
代码长度限制16000 B
判题程序Standard作者CHEN, Yue
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.
![]()
![]()
![]()
![]()
Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (<=20) which is the total number of keys to be inserted. Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print ythe root of the resulting AVL tree in one line.
Sample Input 1:5 88 70 61 96 120Sample Output 1:70Sample Input 2:7 88 70 61 96 120 90 65Sample Output 2:88数据结构听到AVL就头大,根本不知道这么做的意义;这次看着博文和别人AC的代码写了这个。以前很喜欢用链表的;但是现在有点不喜欢,比如地址空间会很大的。然后就用int带代替指针;整个数组化。AVL左旋右旋,旋来旋去就那几行代码。重点的是那个有回溯的那段。还有各种细节;
代码中有详细的注释。顺便(PS:我通过tag动态化,直接就弄成看似一种旋转的了)
有四种种情况可能导致二叉查找树不平衡,分别为:
(1)LL:插入一个新节点到根节点的左子树(Left)的左子树(Left),导致根节点的平衡因子由1变为2
(2)RR:插入一个新节点到根节点的右子树(Right)的右子树(Right),导致根节点的平衡因子由-1变为-2
(3)LR:插入一个新节点到根节点的左子树(Left)的右子树(Right),导致根节点的平衡因子由1变为2
(4)RL:插入一个新节点到根节点的右子树(Right)的左子树(Left),导致根节点的平衡因子由-1变为-2
针对四种种情况可能导致的不平衡,可以通过旋转使之变平衡。有两种基本的旋转:
(1)左旋转:将根节点旋转到(根节点的)右孩子的左孩子位置
(2)右旋转:将根节点旋转到(根节点的)左孩子的右孩子位置
联动AVL http://dongxicheng.org/structure/avl/
评测结果
时间 | 结果 | 得分 | 题目 | 语言 | 用时(ms) | 内存(kB) | 用户 |
---|---|---|---|---|---|---|---|
8月13日 21:56 | 答案正确 | 25 | 1066 | C++ (g++ 4.7.2) | 1 | 308 | datrilla |
测试点
测试点 | 结果 | 用时(ms) | 内存(kB) | 得分/满分 |
---|---|---|---|---|
0 | 答案正确 | 1 | 308 | 4/4 |
1 | 答案正确 | 1 | 308 | 4/4 |
2 | 答案正确 | 1 | 308 | 4/4 |
3 | 答案正确 | 1 | 308 | 4/4 |
4 | 答案正确 | 1 | 308 | 4/4 |
5 | 答案正确 | 1 | 308 | 4/4 |
6 | 答案正确 | 1 | 308 | 1/1 |
#include <iostream> #include<vector> using namespace std; struct List { int value; int left_right; int l0_r1[2]; }; int Height(vector<List>*AVLtree, int node,int tag)/*如果node的child【左tag=0】【右tag=1】不存在那么返回高度-1 */ { /*如果node存在,那么必然返回对应结点child的|left-right|>=0*/ int child = (*AVLtree)[node].l0_r1[tag]; /*PS:本来一直样例不行,原来是存在时错误返回node前一轮的了*/ if (child == -1)return -1; else return (*AVLtree)[child].left_right; } int returnmax(int a, int b)/*对于root返回他的左右结点高度最高的*/ { if (a > b)return a; else return b; } int rotate(vector<List>*AVLtree,int tag,int Root,int child)/*tag=0,左旋:带入的child为Root的右。[1-tag]→;[tag]←*/ { /*tag=1,右旋:带入的child为Root的左。[1-tag]←;[tag]→*/ (*AVLtree)[Root].l0_r1[1-tag] = (*AVLtree)[child].l0_r1[tag]; (*AVLtree)[child].l0_r1[tag] = Root; (*AVLtree)[Root].left_right = returnmax(Height(AVLtree, Root, tag), Height(AVLtree, Root, 1-tag))+1; (*AVLtree)[child].left_right = returnmax(Height(AVLtree, child, tag), Height(AVLtree, child, 1 - tag))+1; return child; /*旋转以后Root和Child身份互换了,并且稳定,需要更新此时他们的高度,一遍回溯的时候由其他Root使用*/ } int insertnew(vector<List>*AVLtree, int Root,int N) { int tag; int child; if (Root == N) return Root; /*只有一个结点,显然这个结点就是Root【PS第一次的Root,在主函数有初始化为最开始的N-1】*/ else { if ((*AVLtree)[N].value < (*AVLtree)[Root].value)/*本来已经存在结点,这里用来判断是往左走tag=0,或者往右走tag=1*/ tag = 0; else tag = 1; if ((*AVLtree)[Root].l0_r1[tag] != -1)/*如果此次走的Root的该方向还有下个结点,DFS走下去;否则截止*/ { child = (*AVLtree)[Root].l0_r1[tag] = insertnew(AVLtree, (*AVLtree)[Root].l0_r1[tag], N); /*这里出来以后的child为新数往当前Root走的方向稳定后的【左tag=0】【右tag=1】结点*/ if (Height(AVLtree, Root, tag) - Height(AVLtree, Root, 1 - tag) == 2) { if ( ( (*AVLtree)[N].value<(*AVLtree)[Root].value &&(*AVLtree)[N].value<(*AVLtree)[child].value )|| ( (*AVLtree)[N].value>=(*AVLtree)[Root].value && (*AVLtree)[N].value>=(*AVLtree)[child].value) ) { Root=rotate(AVLtree,1-tag, Root, child); }/*R L 如果新放入的在这个child和root的同一边左左(右右),那么只要一次对应左(右)旋*/ else { child = rotate(AVLtree,tag, child, (*AVLtree)[child].l0_r1[1-tag]); Root = rotate(AVLtree,1-tag, Root, child);/**/ }/*LR RL 否则在Root左,child右;左旋后右旋;在Root右,在child左,右旋后左旋*/ } } else child=(*AVLtree)[Root].l0_r1[tag] = N; /*这里是截止的,即新进的位置*/ } (*AVLtree)[Root].left_right = returnmax(Height(AVLtree, Root, tag), Height(AVLtree, Root, 1 - tag)) + 1; return Root; } int main() { int N,Root; cin >> N; vector<List>AVLtree(N); Root = N - 1; while (N--) { cin >> AVLtree[N].value; AVLtree[N].left_right = 0; AVLtree[N].l0_r1[0] = AVLtree[N].l0_r1[1] = -1; Root = insertnew(&AVLtree, Root, N); } cout<< AVLtree[Root].value << endl; system("pause"); return 0; }
上面这种思路用[tag]的,有点反人类,很难理清。其实个人觉得分开写或许会更便于理解和书写。
再转一个大佬们的。
#include <cstdio> #define max(a, b) (((a) > (b)) ? (a) : (b)) struct node { int val; struct node *left, *right; }; node *rotateLeft(node *root) { node *t = root->right; root->right = t->left; t->left = root; return t; } node *rotateRight(node *root) { node *t = root->left; root->left = t->right; t->right = root; return t; } node *rotateLeftRight(node *root) { root->left = rotateLeft(root->left); return rotateRight(root); } node *rotateRightLeft(node *root) { root->right = rotateRight(root->right); return rotateLeft(root); } int getHeight(node *root) { if(root == NULL) return 0; return max(getHeight(root->left), getHeight(root->right)) + 1; } node *insert(node *root, int val) { if(root == NULL) { root = new node(); root->val = val; root->left = root->right = NULL; } else if(val < root->val) { root->left = insert(root->left, val); if(getHeight(root->left) - getHeight(root->right) == 2) root = val < root->left->val ? rotateRight(root) : rotateLeftRight(root); } else { root->right = insert(root->right, val); if(getHeight(root->left) - getHeight(root->right) == -2) root = val > root->right->val ? rotateLeft(root) : rotateRightLeft(root); } return root; } int main() { int n, val; scanf("%d", &n); node *root = NULL; for(int i = 0; i < n; i++) { scanf("%d", &val); root = insert(root, val); } printf("%d", root->val); return 0; }