PAT 1066 Root of AVL Tree C++版

本文详细解析了如何使用C++实现AVL树的构建和平衡调整过程,包括左右旋操作、节点高度更新和平衡因子计算等核心步骤。通过具体代码示例,帮助读者深入理解AVL树的运作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PAT 1066 Root of AVL Tree C++版

1.题意

给出一个整数序列,现在需要让你输出以这个序列构建得到的AVL树的根节点。

2.分析

之前我一直都是按照个人的理解做AVL ,对于考试题来说,则是相当简单的,但是如果让我单独实现一棵AVL树,我之前是不会的。但是今天看到晴神的书之后,恍然大悟,又进一步理解到**“算法只不过是一种抽象”**,而代码又只是将这种抽象实现起来罢了。
实现AVL的主要步骤如下:

  • step1:建树
  • setp2:平衡(左右旋)
    这里麻烦的地方就是平衡(即左右旋了)。但是如果我们再次抽象的看整个平衡过程,就是左右旋两种情况的组合罢了,这样就得到了四种旋转过程(左旋;右旋;先左旋,再右旋;先右旋,再左旋)。意思就是我们只需要单独实现一个左右旋,然后组合起来,当需要旋转的时候,调用函数即可。

而在左右旋之前,我们需要判断二叉树是否失衡。这就涉及到求当前节点高度getHeight(),以及判断平衡因子getBF()两个步骤。
而在每次旋转之后(或者是插入新节点之后),我们都需要对影响到的树中节点的高度进行更新updateHeight()
根据上面的分析,得到如下的代码

3.代码
#include<cstdio> 
#include<iostream>
#define maxn 100

using namespace std;

int N ;
struct Node{	 
	Node* left;
	Node* right; 
	int data;//数值
	int height;//高度 
};

Node* newNode(int v){
	Node* node = new Node;//构建一个新节点 
	node->left = NULL;
	node->right = NULL;
	node->data = v;// 
	node->height = 1;//高度为1
	return node; 
}

//更新节点高度 
void updateHeight(Node* root){
	int lh ;
	int rh;
	if(root->left==NULL) lh = 0;
	else lh=root->left->height;
	if(root->right == NULL)  rh = 0;
	else rh=root->right->height;
	root->height = max(lh,rh)+1; 
} 

//获取当前root 节点的高度 
int getHeight(Node* root){
	if(root== NULL)  return 0;
	return root->height;
}

//计算节点root的平衡因子 
int getBF(Node* root){
	return getHeight(root->left) - getHeight(root->right); 
}


//右旋 
void R(Node* &root){
	Node* temp = root->left;
	root->left = temp->right;
	temp->right = root;
	updateHeight(root);
	updateHeight(temp);
	root = temp;//以temp作为根		
}

//左旋 
void L(Node* &root){
	Node* temp = root->right;
	root->right = temp->left;
	temp->left = root;
	updateHeight(root);
	updateHeight(temp);
	root = temp;//以temp作为根		
}


//插入值 
void insert(Node* &root,int v){
	if(root == NULL){//如果root 为NULL 
		root = newNode(v); 
		return; 
	}
	if(v > root->data ){//进入右子树 
		insert(root->right,v) ;
		updateHeight(root);//因为进入了右子树,所以需要更新 当前root的高度 		 		
		if(getBF(root) == -2){//说明右子树高 
			if(getBF(root->right) == -1) L(root);
			else{
				R(root->right);
				L(root);
			}
		}
	}
	else {//进入左子树 
		insert(root->left,v) ;
		updateHeight(root);		
		if(getBF(root) == 2){//左子树高 		
			if(getBF(root->left) == 1) {//LL型 
				//直接右旋 
				R(root);				
			}
			else{//LR型 
				//先左旋,再右旋
				L(root->left);
				R(root); 
			} 
		}
	}
}


int main(){
	cin >> N;
	int v;//当前需要插入的值	
	int i,j;
	Node* root = NULL;//作为根节点 
	for(i = 0;i< N;i++){
		cin >> v;
		insert(root,v) ;					
	}	
	cout << root->data;
}
4.测试用例
3
88 70 61

5
88 70 61 96 120

7
88 70 61 96 120 90 65
5.执行结果

在这里插入图片描述
开心的事儿就是一次AC啦,啦啦啦啦

6.注意点
  • LL,LR,RL, RR代表的都是树型,而不是左右旋!!LR代表的就是树型先往左偏,再往右偏的情况。如下图所示:
    a
    RR代表的就是全都右偏的树型。如下所示:
    在这里插入图片描述
    其它的类似,这里不再分析。

  • 在调整树型的时候,需要注意,如果是LL,或者是RR型,直接对root进行右旋或者左旋;但是如果树型是LR,或者是RL,则需要先对root的左子树,或是root的右子树进行旋转,然后再对root进行旋转。

  • 最后给出一副手绘图,用以表示左右旋的过程。
    在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

说文科技

看书人不妨赏个酒钱?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值