AVL平衡二叉树原理与代码实现过程详解

什么时平衡二叉树

平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

//定义一颗平衡二叉树的节点
template <class T>
struct AVLtreeNode{
	T data;
	AVLtreeNode<T>* lchild, * rchild;
	AVLtreeNode(T x){
		data=x;
		lchild=NULL;
		rchild=NULL;
	}
	AVLtreeNode(AVLtreeNode* n) { 
		data=n->data;
		lchild=n->lchild;
		rchild=n->rchild;
	}
};

二叉树的高度

注意区分二叉树的深度和高度。

  • 深度是从上到下计算
  • 高度是从下到上计算

int height(AVLtreeNode<T>* node){
	if (node == NULL)
		return 0;
	return std::max(height(node->lchild), height(node->rchild)) + 1;
}

平衡因子

  • 某结点的左子树与右子树的高度(深度)差即为该结点的平衡因子(BF,Balance Factor)。平衡二叉树上所有结点的平衡因子只可能是 -1,0 或 1。如果某一结点的平衡因子绝对值大于1则说明此树不是平衡二叉树。为了方便计算每一结点的平衡因子我们可以为每个节点赋予height这一属性,表示此节点的高度。
int balance_fector(AVLtreeNode<T>* node){
	if (node == NULL)
		return 0;
	return height(node->lchild) - height(node->rchild);
}

四种旋转方式

  1. 右旋
  • 设不平衡节点为根节点(20),其左节点(15)拿出当新根节点,左节点(15)的右节点给根节点(20)做其新左节点,左节点的右节点为新根节点。

在这里插入图片描述
在这里插入图片描述

AVLtreeNode<T>* RightMove(AVLtreeNode<T>* node){
	AVLtreeNode<T>* left = node->lchild;
	node->lchild = left->rchild;
	left->rchild = node;
	return left;
}
  1. 左旋
  • 设不平衡节点为根节点(10),其右节点(20)拿出当新根节点,右节点(20)的左节点给根节点(10)做其新右节点,右节点的左节点为新根节点。

在这里插入图片描述

在这里插入图片描述

AVLtreeNode<T>* LeftMove(AVLtreeNode<T>* node){
	AVLtreeNode<T>* right = node->rchild;
	node->lchild = right->lchild;
	right->lchild = node;
	return right;
}
  1. 左右旋
  • 先对不平衡节点的左节点做一次左旋,旋转之后变为情况一,之后再对不平衡节点做一次右旋

在这里插入图片描述
在这里插入图片描述

AVLtreeNode<T>* LeftRightMove(AVLtreeNode<T>* node){
	node->lchild = LeftMove(node->lchild);
	return RightMove(node);
}
  1. 右左旋
  • 先对不平衡节点的右节点做一次右旋,旋转之后变为情况二,之后再对不平衡节点做一次左旋

在这里插入图片描述
在这里插入图片描述

AVLtreeNode<T>* RightLeftMove(AVLtreeNode<T>* node){
	node->rchild = RightMove(node->rchild);
	return LeftMove(node);
}

判断何时用何种旋转

  • 当一个节点的左右子树高度之差大于1或小于-1时,该节点需要进行平衡旋转操作
  1. 平衡因子为2时,说明左子树高度比右子树高2,再次判断其左节点的平衡因子,若大于0就右旋,小于0就要左右旋。
  2. 平衡因子为-2时,说明右子树高度比左子树高2,再次判断其右节点的平衡因子,若小于0就左旋,大于0就要右左旋。

下面展示平衡因子为2的两种情况,平衡因子为-2同理。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


AVLtreeNode<T>* rebalance(AVLtreeNode<T>* node){
	int fector = balance_fector(node);
	if (fector == 2)//平衡因子为2肯定需要一步左旋或者先左旋再右旋{
		if (balance_fector(node->lchild) > 0)
			node = RightMove(node);
		else
			node = LeftRightMove(node);
	}
	if (fector == -2){//平衡因子为2肯定需要一步右旋或者先右旋再左旋
		if (balance_fector(node->rchild) < 0)
			node = LeftMove(node);
		else
			node = RightLeftMove(node);
	}
	return node;
}

AVL节点删除

AVLtreeNode<T>* remove(AVLtreeNode<T>* node, const T& val){
		if (node == NULL) return node;
		if (val < node->data){
			node->lchild = remove(node->lchild, val);
		}
		else if (val > node->data){
			node->rchild = remove(node->rchild, val);
		}
		else{
			if (node->lchild ==NULL){
				AVLtreeNode<T>* del = node;
				node = node->rchild;
				delete del;
			}
			else if (node->rchild == nullptr){
				AVLtreeNode<T>* del = node;
				node = node->lchild;
				delete del;
			}
			else{
				AVLtreeNode<T>* successor = new AVLtreeNode<T>(minimum(node->rchild));
				node->rchild = remove(node->rchild, successor->data);
				successor->lchild = node->lchild;
				successor->rchild = node->rchild;
				delete node;
				node = successor;
			}
		}
		return rebalance(node);
	}

AVL完整代码实现流程

#include<iostream>
#include <algorithm>
using namespace std;

template <class T>
struct AVLtreeNode
{
	T data;
	AVLtreeNode<T>* lchild, * rchild;
	AVLtreeNode(T x)
	{

		data=x;
		lchild=NULL;
		rchild=NULL;
	}
	AVLtreeNode(AVLtreeNode* n) 
	{ 
		data=n->data;
		lchild=n->lchild;
		rchild=n->rchild;
	}

};
template <class T>
class AVLTree
{
public:
	AVLTree()
	{
		root=NULL;
	}
	~AVLTree()
	{
		destory(root);
	}
	void destory(AVLtreeNode<T>* node)
	{
		if (node != NULL)
		{
			destory(node->lchild);
			destory(node->rchild);
			delete node;
		}
	}
    int height(AVLtreeNode<T>* node)
	{
		if (node == NULL)
			return 0;
		return std::max(height(node->lchild), height(node->rchild)) + 1;
	}
	int balance_fector(AVLtreeNode<T>* node)
	{
		if (node == NULL)
			return 0;
		return height(node->lchild) - height(node->rchild);
	}
	AVLtreeNode<T>* RightMove(AVLtreeNode<T>* node)
	{
		AVLtreeNode<T>* left = node->lchild;
		node->lchild = left->rchild;
		left->rchild = node;
		return left;
	}
	AVLtreeNode<T>* LeftMove(AVLtreeNode<T>* node)
	{
		AVLtreeNode<T>* right = node->rchild;
		node->lchild = right->lchild;
		right->lchild = node;
		return right;
	}
	AVLtreeNode<T>* LeftRightMove(AVLtreeNode<T>* node)
	{
		node->lchild = LeftMove(node->lchild);
		return RightMove(node);
	}
	AVLtreeNode<T>* RightLeftMove(AVLtreeNode<T>* node)
	{
		node->rchild = RightMove(node->rchild);
		return LeftMove(node);
	}
	AVLtreeNode<T>* insert(AVLtreeNode<T>* node, const T& val)
	{
		if (node == NULL)
			return new AVLtreeNode<T>(val);
		if (val == node->data)
			return node;
		if (val < node->data)
			node->lchild = insert(node->lchild, val);
		else
			node->rchild = insert(node->rchild, val);
		return rebalance(node);
	}
	AVLtreeNode<T>* rebalance(AVLtreeNode<T>* node)
	{
		int fector = balance_fector(node);
		if (fector == 2)//平衡因子为2肯定需要一步左旋或者先左旋再右旋
		{
			if (balance_fector(node->lchild) > 0)
				node = RightMove(node);
			else
				node = LeftRightMove(node);
		}
		if (fector == -2)//平衡因子为2肯定需要一步右旋或者先右旋再左旋
		{
			if (balance_fector(node->rchild) < 0)
				node = LeftMove(node);
			else
				node = RightLeftMove(node);
		}
		return node;
	}
	AVLtreeNode<T>* remove(AVLtreeNode<T>* node, const T& val)
	{
		if (node == NULL) return node;
		if (val < node->data)
		{
			node->lchild = remove(node->lchild, val);
		}
		else if (val > node->data)
		{
			node->rchild = remove(node->rchild, val);
		}
		else
		{
			if (node->lchild ==NULL)
			{
				AVLtreeNode<T>* del = node;
				node = node->rchild;
				delete del;
			}
			else if (node->rchild == nullptr)
			{
				AVLtreeNode<T>* del = node;
				node = node->lchild;
				delete del;
			}
			else
			{
				AVLtreeNode<T>* successor = new AVLtreeNode<T>(minimum(node->rchild));
				node->rchild = remove(node->rchild, successor->data);
				successor->lchild = node->lchild;
				successor->rchild = node->rchild;
				delete node;
				node = successor;
			}
		}
		return rebalance(node);
	}
	void insert(const T& val)
	{
		root = insert(root, val);
	}
	void remove(const T& val)
	{
		root = remove(root, val);
	}
	AVLtreeNode<T>* get_root()
	{
		return root;
	}
	AVLtreeNode<T>* minimum(AVLtreeNode<T>* node)
	{
		while (node->lchild)
		{
			node = node->lchild;
		}
		return node;
	}
	void output(AVLtreeNode<T>* p)
	{
		if (p != NULL)
		{
			output(p->lchild);
			cout << p->data << " ";
			output(p->rchild);
		}
	}
private:
	AVLtreeNode<T>* root;
};
int main()
{
	AVLTree<int> a;
	a.insert(30);
	a.insert(5);
	a.insert(40);
	a.insert(35);
	a.output(a.get_root());
	cout << endl;
	a.insert(32);
	a.output(a.get_root());
	cout << endl;
	a.remove(30);
	a.output(a.get_root());
	return 0;
}

验证二叉搜索树

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    int tra=INT_MIN;
public:
    bool isValidBST(TreeNode* root) {
        if(!root) return true;
        bool left=isValidBST(root->left);
        if(root->val>tra){
            tra=root->val;
        }
        else
            return false;
        bool right=isValidBST(root->right);
        return left&&right;
    }
};

二叉搜索树最小差值

在这里插入图片描述

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    TreeNode* pre=nullptr;
    int minnum=INT_MAX;
    void traversal(TreeNode* node){
        if(!node) return;
        traversal(node->left);
        if(pre){
            minnum=min(minnum,node->val-pre->val);
        }
        pre=node;
        traversal(node->right);
    }
public:
    int getMinimumDifference(TreeNode* root) {
        traversal(root);
        return minnum;
    }
};

二叉搜索树的众数

在这里插入图片描述

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    int cnt=1;
    int maxcnt=1;
    TreeNode* pre=nullptr;
    vector<int> res;
    void traversal(TreeNode* cur){
        if(!cur) return;
        traversal(cur->left);
        if(pre){
            if(pre->val==cur->val){
                cnt++;
            }
            else cnt=1;
        }
        pre=cur;
        if(cnt==maxcnt){
            res.push_back(cur->val);
        }
        if(cnt>maxcnt){
            res.clear();
            res.push_back(cur->val);
            maxcnt=cnt;
        }
        traversal(cur->right);
    }
public:
    vector<int> findMode(TreeNode* root) {
        traversal(root);
        return res;
    }
};

二叉搜索树的插入

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if (root == NULL) {
            TreeNode* node = new TreeNode(val);
            return node;
        }
        if (root->val > val) root->left = insertIntoBST(root->left, val);
        if (root->val < val) root->right = insertIntoBST(root->right, val);
        return root;
    }
};

二叉搜索树的删除

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if (root == nullptr) return root;
        if (root->val > key) root->left = deleteNode(root->left, key);
        if (root->val < key) root->right = deleteNode(root->right, key); // 第一种情况:没找到删除的节点,遍历到空节点直接返回了
        if (root->val == key) {
            // 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
            // 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点
            if (root->left == nullptr){
                TreeNode* del=root;
                root=root->right;
                delete(del);
            } 
            // 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
            else if (root->right == nullptr){
                TreeNode* del=root;
                root=root->right;
                delete(del);
            } 
            // 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
            // 并返回删除节点右孩子为新的根节点。
            else {
                TreeNode* cur = root->right; // 找右子树最左面的节点
                while(cur->left != nullptr) {
                    cur = cur->left;
                }
                cur->left = root->left; // 把要删除的节点(root)左子树放在cur的左孩子的位置
                TreeNode* tmp = root;   // 把root节点保存一下,下面来删除
                root = root->right;     // 返回旧root的右孩子作为新root
                delete tmp;             // 释放节点内存(这里不写也可以,但C++最好手动释放一下吧)
                return root;
            }
        }
        
        return root;
    }
};
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

VioletEvergarden丶

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值