平衡二叉树AVL树的创建,平衡,和删除节点,c/c++描述

  平衡二叉树的左右子树的高度差小于等于1。或者说其左子树的高度减去右子树的高度,差值的绝对值小于等于1。平衡二叉树,仍然属于排序二叉树。其中序排列里,节点的关键字仍然按递增有序排列。
  为了纪念对平衡二叉树的研究做出贡献的前苏联科学家,取其姓氏里的字母,平衡二叉树,也叫做AVL树。
  每往AVL树里插入一个节点,由函数insertBST完成插入。都要对树里节点进行校平。
  校平由函数checkBalance 完成,计算树里每个节点的平衡因子。可由后序递归完成(按节点左右根的顺序,依次校平每个节点的平衡因子)。
  校平时,若发现某个节点处出现了不平衡,就相当于找到了以该节点为根的最小不平衡子树,对其进行恢复平衡操作,由函数recoverBalance完成。恢复后,最小不平衡子树外的节点不用再校平了(当然递归无法在此时停止)。因为通过对LL、RR、LR、RL的校平过程可以总结出:校平后,原最小不平衡子树的高度并没有因为新节点的插入而发生改变。所以该子树对子树外节点的平衡因子不构成影响。
  因为每插入一个节点,都进行校平,所以树里的最小不平衡子树最多只有一个。
  校平依据的原理:校平时,并不改变最小不平衡子树的中序遍历序列,因为树的平衡与否,其仍然属于排序树。若校平后树的中序遍历序列发生了改变,一定是校平出错了。从而,我们可以得出一个校平方案:依据中序遍历序列里节点的位置,判断哪些节点的指向关系需要改变。而不再区分什么左旋转,右旋转这些不直观的概念。此算法也受到了BST删除节点的算法启发。两者思路是一样的。理解前者的程序组织过程,有利于此处校平的思路掌握。前者同样见懒猫老师的精彩讲解。
  补充一点:函数int checkBalance(Node*& root) :其返回值是以形参节点为根的树的高度。因为校平时,根节点平衡因子的取值与其左右子树的高度有关。这也是平衡因子的定义。所以,有必要计算所有节点的高度(此高度值以叶节点的高度为1,根节点高度是树里最大的)。
  感谢bilibili懒猫老师的精彩讲解:懒猫老师-数据结构-(59)平衡二叉树【互动视频】_哔哩哔哩_bilibili
https://www.bilibili.com/video/BV1kT4y1w7Cx
  本程序是在BST树的程序基础上加工完善而来的,程序的其ta介绍见
https://blog.csdn.net/zhangzhangkeji/article/details/119706654
  完整代码如下,先是main函数所在源文件:

#include<iostream>
using namespace std;

struct Node {
	int balanceFactor;
	int data;
	Node* ptLeftChild;
	Node* ptRightChild;
};

extern void insertBST(Node * & root,int data);
extern void inOrderTraverse(Node*& root);
extern void displayBST(Node*& root);
extern bool deleteKey(Node*& root,int key);
extern void deletePt(Node *& ptDelete);
extern int checkBalance(Node*& root);
extern void recoverBalance(Node * & root);

int main() {
	int a[] = {4,9,0,1,8,6,3,5,2,7},length = 10;
	Node* root = NULL;

	for (int i = 0; i < length; i++) {
		insertBST(root, a[i]);
		checkBalance(root);
	}

	cout << "middle order traverse : ";
	inOrderTraverse(root);

	cout<<endl<<"逗号表达式表示该 AVL 树 :";
	displayBST(root);

	cout<<endl << "delete 8 : ";
	deleteKey(root,8);
	checkBalance(root);
	displayBST(root);

	cout << endl << "delete 2 : ";
	deleteKey(root, 2);
	checkBalance(root);
	displayBST(root);

	return 0;
}

接着是各函数所在源文件:

#include<iostream>
using namespace std;

struct Node {
	int balanceFactor;
	int data;
	Node* ptLeftChild;
	Node* ptRightChild;
};

void insertBST(Node*& root, int data) {
	if (root == NULL) {
		root = new Node;
		root->balanceFactor = 0;
		root->data = data;
		root->ptLeftChild = root->ptRightChild = NULL;
		return;
	}

	if (root->data > data)
		insertBST(root->ptLeftChild, data);
	else if (root->data < data)
		insertBST(root->ptRightChild,data);
	else 
		cout << "key " <<data<<" repeated ! " << endl;
}

void inOrderTraverse(Node*& root) {
	if (root == NULL)
		return;

	inOrderTraverse(root->ptLeftChild);
	cout << root->data << ' ';
	inOrderTraverse(root->ptRightChild);
}

void displayBST(Node*& root) {
	if (root == NULL)
		return;

	cout << root->data;
	if (root->ptLeftChild != NULL || root->ptRightChild != NULL) {
		cout << '(';
		displayBST(root->ptLeftChild);
		
		if (root->ptRightChild != NULL) {
			cout << ',';
			displayBST(root->ptRightChild);
		}

		cout << ')';
	}
}

bool deleteKey(Node*& root, int key) {
	void deletePt(Node * &ptDelete);

	if (root == NULL)
		return false;

	if (root->data > key)
		return deleteKey(root->ptLeftChild, key);
	else if (root->data < key)
		return deleteKey(root->ptRightChild, key);
	else
		deletePt(root);

	return true;
}

void deletePt(Node* & ptDelete) {
	Node* ptTemp;
	if (ptDelete->ptLeftChild == NULL && ptDelete->ptRightChild == NULL) {
		ptTemp = ptDelete;
		ptDelete = NULL;
		delete ptTemp;
	}
	else if (ptDelete->ptLeftChild == NULL) {
		ptTemp = ptDelete;
		ptDelete = ptDelete->ptRightChild;
		delete ptTemp;
	}
	else if (ptDelete->ptRightChild == NULL) {
		ptTemp = ptDelete;
		ptDelete = ptDelete->ptLeftChild;
		delete ptTemp;
	}
	else {
		Node* ptParentTemp = ptDelete;
		ptTemp = ptDelete->ptLeftChild;
	
		while (ptTemp->ptRightChild != NULL) {
			ptParentTemp = ptTemp;
			ptTemp = ptTemp->ptRightChild;
		}
	
		//情况1 : root = ptDelete = ptParentTemp , ptTemp = root.ptLeftChild
		//情况2 : root = ptDelete != ptParentTemp , ptTemp = ptParentTemp.ptLeftChild
		//情况3 : root != ptDelete = ptParentTemp , ptTemp = ptDelete.ptLeftChild
		//情况4 : root != ptDelete != ptParentTemp , ptTemp = ptParentTemp.ptLeftChild
		ptDelete->data = ptTemp->data;
		if (ptParentTemp == ptDelete)  //左子树的最大节点是否是左子树的根节点
			ptDelete->ptLeftChild = ptTemp->ptLeftChild;
		else
			ptParentTemp->ptRightChild = ptTemp->ptLeftChild;
		
		delete ptTemp;
	}
}

void recoverBalance(Node*& root) {
	Node* ptTemp;
	if (root->balanceFactor == 2 && root->ptLeftChild->balanceFactor == 1) {
		ptTemp = root->ptLeftChild;
		
		root->ptLeftChild = ptTemp->ptRightChild;
		ptTemp->ptRightChild = root;
		root = ptTemp;
	}
	else if (root->balanceFactor == 2 && root->ptLeftChild->balanceFactor == -1) {
		ptTemp = root->ptLeftChild->ptRightChild;
	
		root->ptLeftChild->ptRightChild = ptTemp->ptLeftChild;
		ptTemp->ptLeftChild = root->ptLeftChild;
		root->ptLeftChild = ptTemp->ptRightChild;
		ptTemp->ptRightChild = root;
		root = ptTemp;
	}
	else if (root->balanceFactor == -2 && root->ptRightChild->balanceFactor == -1) {
		ptTemp = root->ptRightChild;
	
		root->ptRightChild = ptTemp->ptLeftChild;
		ptTemp->ptLeftChild = root ;
		root = ptTemp;
	}
	else if (root->balanceFactor == -2 && root->ptRightChild->balanceFactor == 1) {
		ptTemp = root->ptRightChild->ptLeftChild;

		root->ptRightChild->ptLeftChild = ptTemp->ptRightChild;
		ptTemp->ptRightChild = root->ptRightChild;
		root->ptRightChild = ptTemp->ptLeftChild;
		ptTemp->ptLeftChild = root;
		root = ptTemp;
	}
}

int  checkBalance(Node*& root) {
	if (root == NULL)
		return 0;

	int heightLeft, heightRight;
	heightLeft = checkBalance(root->ptLeftChild);
	heightRight = checkBalance(root->ptRightChild);

	root->balanceFactor = heightLeft - heightRight;
	if (root->balanceFactor == 2 || root->balanceFactor == -2) {
		recoverBalance(root);
		return (heightLeft > heightRight) ? heightLeft : heightRight ;
	}
	else
		return (heightLeft > heightRight) ? heightLeft + 1 : heightRight + 1;
}

测试结果与课本答案与对应的图如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
谢谢阅读。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值