PAT 1066. Root of AVL Tree (25) 回レ!雪月AVL

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 120
Sample Output 1:
70
Sample Input 2:
7 88 70 61 96 120 90 65
Sample 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答案正确251066C++ (g++ 4.7.2)1308datrilla

测试点

测试点结果用时(ms)内存(kB)得分/满分
0答案正确13084/4
1答案正确13084/4
2答案正确13084/4
3答案正确13084/4
4答案正确13084/4
5答案正确13084/4
6答案正确13081/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;
}



                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值