【个人代码及思路】PAT甲级:1066 Root of AVL Tree (25分)

PAT (Advanced Level) Practice

1066 Root of AVL Tree (25分)

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.

img img

img img

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 the 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

个人代码:

#include <stdio.h>
#include <algorithm>
// #define LOCAL

using namespace std;

typedef struct AVLNode {                              //AVL树结点
   int height, val;
   struct AVLNode *lchild, *rchild, *parent;
} AVLNode, *AVLTree;

// void InitAVLTree (AVLTree &T) {                    //初始化
//    T -> lheight = 0;
//    T -> rheight = 0;
//    T -> lchild = NULL;
//    T -> rchlid = NULL;
//    T -> parent = NULL;
// }

AVLNode *AVLTreeInsert (AVLTree &T, int val) {        //插入新的结点
   if (T == NULL) {
      T = (AVLTree)malloc(sizeof(AVLNode));
      T->val = val;
      T->lchild = NULL;
      T->rchild = NULL;
      T->parent = NULL;
      return T;
   } else if (val < T->val) {
      return AVLTreeInsert(T->lchild, val);
   } else {
      return AVLTreeInsert(T->rchild, val);
   }
}

int AVLTreeHeight (AVLTree &T) {                      //求高度
   if (T == NULL) {
      return 0;
   } else {
      int lheight, rheight;
      lheight = AVLTreeHeight(T->lchild);
      rheight = AVLTreeHeight(T->rchild);
      T->height = max(lheight + 1, rheight + 1);
      //   printf("%d*\n", T -> height);
      return T->height;
   }
}

void SetParent (AVLTree &T) {                         //设置双亲结点
   if (T == NULL) {
      return; 
   }
   if (T->lchild != NULL) {
      T->lchild->parent = T;
      SetParent(T->lchild);
   }
   if (T->rchild != NULL) {
      T->rchild->parent = T;
      SetParent(T->rchild);
   }
}

void AVLTreeLrevov (AVLTree &p, AVLTree &T) {         //左旋操作
   if (p->parent->parent != NULL) {
      if (p->parent->val < p->parent->parent->val) {
         p->parent->parent->lchild = p;
      } else {
         p->parent->parent->rchild = p;
      }
   }
   p->parent->rchild = p->lchild;
   p->lchild = p->parent;
   if (p->lchild->val == T->val) {
      T = p;
      T->parent = NULL;
   }
}

void AVLTreeRrevov (AVLTree &p, AVLTree &T) {         //右旋操作
   if (p->parent->parent != NULL) {                   //首先判断该结点
      if (p->parent->val < p->parent->parent->val) {
         p->parent->parent->lchild = p;
      } else {
         p->parent->parent->rchild = p;
      }
   }
   p->parent->lchild = p->rchild;
   p->rchild = p->parent;
   if (p->rchild->val == T->val) {
      T = p;
      T->parent = NULL;
   }
}

// void visit (AVLTree T) {                           //前序遍历
//     if (T != NULL) {
//       printf("T->val=%d,T->height=%d--\n",T->val, T->height);
//       visit (T->lchild);
//       visit (T->rchild);
//    }
// }

int main () {
#ifdef LOCAL
   freopen("./in.txt", "r", stdin);
   // freopen("./out.txt", "w", stdout);
#endif
   int n;
   scanf("%d", &n);
   AVLTree T = NULL;
   AVLNode *p = NULL;
   // InitAVLTree (T);
   for (int i = 0; i < n; i++) {
      int lheight = 0, rheight = 0, value = 0;        //左子树高度、右子树高度、值
      int revov = 0;                                  //标志需要进行的旋转操作,0-4代表结点类型,不操作,LL,LR,RL,RR
      scanf("%d", &value);
      p = AVLTreeInsert(T, value);
      AVLTreeHeight(T);
      SetParent(T);
      while (p != NULL) {                             //找到第一个不平衡结点
         if (p->lchild != NULL) {                     //左子树高度
            lheight = p->lchild->height;
         } else {
            lheight = 0;
         }
         if (p->rchild != NULL) {                     //右子树高度
            rheight = p->rchild->height;
         } else {
            rheight = 0;
         }
         if (abs(lheight - rheight) < 2) {            //从插入点往上寻找双亲结点,使p为第一个不平衡结点
            p = p->parent;
         } else break;
      }
      if (abs(lheight - rheight) >= 2) {              //p可能为NULL,可能为第一个不平衡结点
         if (value < p->val) {
            p = p->lchild;                            //需要进行LL/LR旋转操作
            if (value < p->val) {
               revov = 1;                             //LL旋转操作
            } else {
               revov = 2;                             //LR旋转操作
            }
         } else {
            p = p->rchild;                           //需要进行RL/RR旋转操作
            if (value < p->val) {
               revov = 3;                            //RL旋转操作
            } else {
               revov = 4;                            //RR旋转操作
            }
         }
      }
      switch (revov) {                                //根据不平衡点类型选择旋转操作,旋转后注意重新设置双亲结点
      case 0:                                         //不是不平衡点,不进行操作
         break;
      case 1:                                         //LL类型进行右旋操作
         AVLTreeRrevov(p, T);
         SetParent(T);
         break;
      case 2:                                         //LR类型先进行左旋操作再进行右旋操作
         p = p->rchild;
         AVLTreeLrevov(p, T);
         SetParent(T);
         AVLTreeRrevov(p, T);
         SetParent(T);
         break;
      case 3:                                         //RL类型先进行右旋操作再进行左旋操作
         p = p->lchild;                               //旋转的对象是
         AVLTreeRrevov(p, T);
         SetParent(T);
         AVLTreeLrevov(p, T);
         SetParent(T);
         break;
      case 4:                                         //RR类型进行左旋操作
         AVLTreeLrevov(p, T);
         SetParent(T);
         break;
      }
      // visit(T);                                    //遍历一遍AVL树,检查是否正确
   }
   printf("%d", T->val);                              //已经成功构建AVL树,选择自己的操作
   return 0;
}

思路提示:

建立AVL树的步骤如下:

  • 首先定义AVL树的结点,包含高度、值、指向孩子结点和双亲结点的指针等信息
  • 每读入一个结点,就要将他按照BST的排序规则插入AVL树中
  • 每个结点插入后,检查AVL树中每个结点是否满足左右子树高度相差的绝对值不超过1,方法是从刚插入的结点往上找他的双亲结点(设置双亲结点的好处)
  • 找到最近的一个不满足平衡条件的结点,根据LL、LR、RL、RR四种类型确定需要进行旋转的操作和对象
  • 注意,当树的高度和双亲节点变化后,需要及时的通过函数更新
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值