PAT甲级 -- 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.

 

 

 

 

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

我的思路:

AVL树在大学数据结构里面学过,但不是重点要求掌握,但是以后必定是常用的数据结构,看到这道题,只知道AVL树的结构特点,把怎么进行平衡全部忘了,于是乎,翻开书本进行复习!

 

AVL树的插入和平衡调整

(1)思想:每当在二叉排序树中插入或删除一个结点时,首先检查再插入路径上的结点是否因此次插入导致不平衡。若导致不平衡,先找到插入路径上离插入结点最近的平衡因子的绝对值大于1的结点A,再对以A为根的子树进行调整,使之达到平衡。

失去平衡后进行调整的规律归纳为4种:

(1)LL平衡旋转(右单旋转):在A的L孩子的L子树上插入新结点,导致A平衡因子增至2。将A的左孩子B向右上旋转代替A成为根节点,将A结点向右下旋转成为B的右子树的根节点,而B的原右子树则作为A结点的左子树。

(2)RR平衡旋转(左单旋转):在A的R孩子的R子树上插入新结点,导致A平衡因子减至-2。将A的右孩子B向左上旋转代替A成为根节点,将A结点向左下旋转成为B的左子树的根节点,而B的原左子树则作为A结点的右子树。

(3)LR平衡旋转(先左后右双旋转):在A的L孩子的R子树上插入新结点,导致A平衡因子增至2。做两次旋转,先左旋后右旋。根节点左孩子进行左旋,然后再对根进行右旋。

(4)RL平衡旋转(先右后左双旋转):在A的R孩子的L子树上插入新结点,导致A平衡因子减至-2。做两次旋转,先右旋后左旋。根节点右孩子进行右旋,然后再对根进行左旋。

(5)getHeight表示获取传入结点的子树的高度

(6)build插入建树的过程:如果root为空,直接新建结点插入,如果当前要插入的值小于root->val,则插入root的左子树;如果当前要插入的值大于root->val,则插入root的右子树~如果插入后左右子树高度差大于1,再根据值的大小比较进行旋转调整使树平衡。插入完成后返回root指针。

 

参考柳神:

        不得不说,这种题就是靠AVL树调整平衡模板代码的记忆,没有多余的数学思维什么的~理解的基础上进行记忆,在做题的时候提高速度!

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
int n;
struct node{
	int value;
	node* lchild, *rchild;
};

node* rotateRight(node* root){ //LL
	node* t = root->lchild;
	root->lchild = t->rchild;
	t->rchild = root;
	
return t;
}
node* rotateLeft(node* root){  //RR
	node* t = root->rchild;
	root->rchild = t->lchild;
	t->lchild = root;
	return t;
}

node* rotateLeftRight(node* root){  //LR
	root->lchild = rotateLeft(root->lchild);
	return rotateRight(root);
}

node* rotateRightLeft(node* root){  //RL
	root->rchild = rotateRight(root->rchild);
	return rotateLeft(root);
}

int getHeight(node* root){
	if(root == NULL) return 0;
	return max(getHeight(root->lchild), getHeight(root->rchild)) + 1;
}

node* build(node* root, int v){
	if(root == NULL){
		root = new node();
		root->value = v;
		root->lchild = root->rchild = NULL;
	}else if(v < root->value){
		root->lchild = build(root->lchild, v);
		if(getHeight(root->lchild) - getHeight(root->rchild) == 2){
			root = v < root->lchild->value? rotateRight(root) : rotateLeftRight(root);
		}
	}else{
		root->rchild = build(root->rchild, v);
		if(getHeight(root->lchild) - getHeight(root->rchild) == -2){
			root = v > root->rchild->value? rotateLeft(root) : rotateRightLeft(root);
		}
	}
	return root;
}

int main(){
	scanf("%d" ,&n);
	int key;
	node* root = NULL;
	for(int i = 0; i < n; i++){
		scanf("%d", &key);
		root = build(root, key);
	}
	printf("%d", root->value);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值