二叉平衡树c++类形式编写详解

目录

 

AVL的定义

为什么要调整

树高

树的旋转调整

检查调整

树结点的插入

树结点的删除

完整代码

AVLTree.h

AVTTree.cpp

test.cpp

测试结果


AVL的定义

平衡二叉查找树:简称平衡二叉树。由前苏联的数学家Adelse-Velskil和Landis在1962年提出的高度平衡的二叉树,根据科学家的英文名也称为AVL树。它具有如下几个性质:

1.可以是空树。

2.假如不是空树,任何一个结点的左子树与右子树都是平衡二叉树,并且高度之差的绝对值不超过1

3.具有二叉查找树所有性质

为什么要调整

平衡二叉树,一定是二叉排序树,之所以将排序树,调整为平衡状态,是为了在二叉排序树近似为链的情况下,增强其查找性能,降低时间复杂度。

树高

记录和更新当前结点的高度是平衡二叉树的核心点,它会告诉你插入或者删除一个节点有没有打破平衡需要进行调整。

树节点


typedef struct TreeAVLNode *treeNode;
struct TreeAVLNode
{
	int val;
	int depth;          //高度
	treeNode lChild;
	treeNode rChild;

	TreeAVLNode(int _val) : val(_val),depth(0), lChild(NULL), rChild(NULL) {}

};

记录更新高度:

void MyAVLTree::update_depth(treeNode& node)
{
	if (node == NULL)
	{
		return;
	}

	int depth_lChild = get_banlance(node->lChild);
	int depth_rChild = get_banlance(node->rChild);
	node->depth = depth_lChild > depth_rChild ? depth_lChild : depth_rChild;
	node->depth++;

	return;
}

int MyAVLTree::get_banlance(treeNode node)
{
	if (node == NULL)
	{
		return 0;
	}

	return node->depth;
}

int MyAVLTree::get_Node_Banlance(treeNode node)
{
	if (node == NULL)
	{
		return 0;
	}

	return get_banlance(node->lChild) - get_banlance(node->rChild);
}

/*
                a4
             b3      c3
          d2            f2
             g1

        字母为节点   数字为高度
     如果此时插入一个节点h位置如下:

                 a5
             b4      c4
          d3            f3
             g2
                h1
d3的平衡因子 = g2 - g2左子树 = -2
此时需要调整
*/

树的旋转调整

平衡因子:树的左子树和右子树高度差绝对值。

什么情况下调整:平衡因子 >=2

void MyAVLTree::rr_Rotate(treeNode& node)
{
	/*
		  3 : node						2
		2							1		3
	  1
	  3的平衡差为2这时候要右旋转		 2和3的层次都有变化需要更新一下
	  2的右孩子给3
	  3成为2的右孩子
	  2替代3的位置
	*/
	treeNode son = node->lChild;
	node->lChild = son->rChild;

	update_depth(node);

	son->rChild = node;
	node = son;

	update_depth(son);
}

void MyAVLTree::ll_Rotate(treeNode& node)
{
	/*
		1 : node													
		  2
		    3
	    1的平衡差为-2这时候要左旋转
		2的左孩子给1
		1成为2的左孩子
		2替代1的位置
	*/

	treeNode son = node->rChild;
	node->rChild = son->lChild;

	update_depth(node);

	son->lChild = node;
	node = son;

	update_depth(son);
}

void MyAVLTree::rl_Rotate(treeNode& node)
{

	rr_Rotate(node->rChild);
	ll_Rotate(node);
}

void MyAVLTree::lr_Rotate(treeNode& node)
{
	ll_Rotate(node->lChild);
	rr_Rotate(node);
}

    /*
          1:node  如果按照 ll转的话   就会成这样        3
              3                                                             1
          2                                                                       2   不行
    所以先以3为node先右转      1
          3:node                     2
        2                               3    再左转
    */

检查调整

就是判断平衡因子不平衡时判断看是哪种上面4种情况的那一种然后调整

代码:

void MyAVLTree::AVLTree(treeNode& node)
{
	int balance = 0;
	update_depth(node);
	balance = get_Node_Banlance(node);
	if (balance > 1)
		leftBalance(node);
	else if (balance < -1)
		rightBalance(node);
	else
		return;
}

void MyAVLTree::leftBalance(treeNode& node)
{
	//左边不平衡  需要右旋转
	if (get_Node_Banlance(node->lChild) < 0)      
	{
		//高度差大于0说明是这样的:
		/*
			4
		  1
		    3
		*/
		lr_Rotate(node);
	}
	else
	{
		rr_Rotate(node);
	}
}

void MyAVLTree::rightBalance(treeNode& node)
{
	//右边不平衡  需要左旋转
	if (get_Node_Banlance(node->rChild) > 0)
	{
		rl_Rotate(node);
	}
	else
	{
		ll_Rotate(node);
	}
}

 

树结点的插入

平衡树的插入在查找树的基础上增加了记录更新树高和检查调整函数

代码:

treeNode MyAVLTree::insertAVLNode(treeNode& root,int val)
{
	if (root == NULL)
	{
		root = new TreeAVLNode(val);
		update_depth(root);
		return root;
	}
	treeNode tmep = NULL;
	if (val < root->val)
	{
		tmep = insertAVLNode(root->lChild, val);
	}
	else if (val > root->val)
	{
		tmep = insertAVLNode(root->rChild, val);
	}

	if (tmep)
	{
		AVLTree(root);      --检查调整树
	}

	return tmep;
}

树结点的删除

考虑4种情况:

1.删除结点不带小孩:删了就行     

2.删除结点带左小孩:代替自己

3.删除结点带右小孩:代替自己

4.删除结点带2小孩:找中序遍历前继结点或者后继结点代替自己

前3点都很简单:

第4点详细看一下:

有如下二叉查找树

                                                             41

                                     13                                        52

                              11         34                          45               82

                                                 40              42        48     60       145

                                                                         46 

中序遍历结果如下:11 .13. 34 .40 .41.42.45.46.48.52.60.82.145

中序遍历的规律是:先左后根再右

假如我们要删除结点52我们该如何调整呢?

找前继或者后继结点 48 . 60

找前继的路径是先左后右  left45 .right48,48的右结点没了就他了

然后把52换成48,把48换成46就行了

找后继先右后左反过来就行

代码:

treeNode MyAVLTree::deleteAVLNode(treeNode& root, int val)
{
	if (root == NULL)
	{
		return NULL;
	}
	treeNode tmep = NULL;
	if (val < root->val)
	{
		tmep = deleteAVLNode(root->lChild, val);
	}
	else if (val > root->val)
	{
		tmep = deleteAVLNode(root->rChild, val);
	}
	else
	{
		return removeNodeForAVL(root);
	}

	if (tmep)
	{
		AVLTree(root);
	}

	return tmep;
}

treeNode MyAVLTree::removeNodeForAVL(treeNode& node)
{
	treeNode pCur;
	treeNode pNext;
	pCur = node;

	if (pCur->rChild == NULL)
	{
		node = pCur->lChild;
		return pCur;
	}
	else if (pCur->lChild == NULL)
	{
		node = pCur->rChild;
		return pCur;
	}
	else
	{
		pNext = pCur->lChild;
		while (pNext->rChild)
		{
			pCur = pNext;
			pNext = pNext->rChild;
		}
		node->val = pNext->val;
		if (pCur != node)
		{
			pCur->rChild = pNext->lChild;
		}
		else
		{
			pCur->lChild = pNext->lChild;
		}
		return pNext;
	}

	return NULL;
}

 

完整代码

AVLTree.h

#ifndef _AVLTREE_H__
#define _AVLTREE_H__
#include<stdio.h>


typedef struct TreeAVLNode *treeNode;
struct TreeAVLNode
{
	int val;
	int depth;          //高度
	treeNode lChild;
	treeNode rChild;

	TreeAVLNode(int _val) : val(_val),depth(0), lChild(NULL), rChild(NULL) {}

};

class MyAVLTree
{
public:
	MyAVLTree();
	~MyAVLTree();

	bool insertNode(int val);

	bool deleteNode(int val);

	void printfTreeByarrangement();
private:
	void freeAllTreeNode(treeNode root);

	void rr_Rotate(treeNode& node);

	void ll_Rotate(treeNode& node);

	void rl_Rotate(treeNode& node);

	void lr_Rotate(treeNode& node);

	void update_depth(treeNode& node);

	int get_banlance(treeNode node);

	int get_Node_Banlance(treeNode node);

	treeNode insertAVLNode(treeNode& root, int val);

	treeNode deleteAVLNode(treeNode& root, int val);

	treeNode removeNodeForAVL(treeNode& node);

	void AVLTree(treeNode& node);

	void leftBalance(treeNode& node);

	void rightBalance(treeNode& node);


private:
	treeNode m_Root;
};

#endif // !_AVLTREE_H__

AVTTree.cpp

#include"AVLTree.h"
#include<vector>
using namespace std;

MyAVLTree::MyAVLTree()
{

}

MyAVLTree::~MyAVLTree()
{
	freeAllTreeNode(m_Root);
}

void MyAVLTree::freeAllTreeNode(treeNode root)
{
	if (NULL == root)
	{
		return;
	}

	treeNode LChild = root->lChild;
	treeNode RChild = root->rChild;

	printf("delete:%d \n", root->val);
	delete root;

	freeAllTreeNode(LChild);
	freeAllTreeNode(RChild);
}

void MyAVLTree::rr_Rotate(treeNode& node)
{
	/*
		  3 : node														2
		2													1		3
	  1
	  3的平衡差为2这时候要右旋转						 2和3的层次都有变化需要更新一下
	  2的右孩子给3
	  3成为2的右孩子
	  2替代3的位置
	*/
	treeNode son = node->lChild;
	node->lChild = son->rChild;

	update_depth(node);

	son->rChild = node;
	node = son;

	update_depth(son);
}

void MyAVLTree::ll_Rotate(treeNode& node)
{
	/*
		1 : node													
		  2
		    3
	    1的平衡差为-2这时候要左旋转
		2的左孩子给1
		1成为2的左孩子
		2替代1的位置
	*/

	treeNode son = node->rChild;
	node->rChild = son->lChild;

	update_depth(node);

	son->lChild = node;
	node = son;

	update_depth(son);
}

void MyAVLTree::rl_Rotate(treeNode& node)
{
	/*
		  1:node             如果按照 ll转的话   就会成这样    3
		    3										        1
		  2												      2   不行
	所以先以3为node先右转      1
		  3:node				2
		2						  3    再左转
	*/
	rr_Rotate(node->rChild);
	ll_Rotate(node);
}

void MyAVLTree::lr_Rotate(treeNode& node)
{
	ll_Rotate(node->lChild);
	rr_Rotate(node);
}

void MyAVLTree::update_depth(treeNode& node)
{
	if (node == NULL)
	{
		return;
	}

	int depth_lChild = get_banlance(node->lChild);
	int depth_rChild = get_banlance(node->rChild);
	node->depth = depth_lChild > depth_rChild ? depth_lChild : depth_rChild;
	node->depth++;

	return;
}

int MyAVLTree::get_banlance(treeNode node)
{
	if (node == NULL)
	{
		return 0;
	}

	return node->depth;
}

int MyAVLTree::get_Node_Banlance(treeNode node)
{
	if (node == NULL)
	{
		return 0;
	}

	return get_banlance(node->lChild) - get_banlance(node->rChild);
}

bool MyAVLTree::insertNode(int val)
{
	treeNode newNode = NULL;

	newNode = insertAVLNode(m_Root, val);

	if (newNode)
	{	
		return true;
	}
	else
	{
		return false;
	}
}

bool MyAVLTree::deleteNode(int val)
{
	treeNode delNode = NULL;

	delNode = deleteAVLNode(m_Root, val);

	if (delNode)
	{
		delete delNode;
		return true;
	}
	else
	{
		return false;
	}
}

void MyAVLTree::AVLTree(treeNode& node)
{
	int balance = 0;
	update_depth(node);
	balance = get_Node_Banlance(node);
	if (balance > 1)
		leftBalance(node);
	else if (balance < -1)
		rightBalance(node);
	else
		return;
}

void MyAVLTree::leftBalance(treeNode& node)
{
	//左边不平衡  需要右旋转
	if (get_Node_Banlance(node->lChild) < 0)      
	{
		//高度差大于0说明是这样的:
		/*
			4
		  1
		    3
		*/
		lr_Rotate(node);
	}
	else
	{
		rr_Rotate(node);
	}
}

void MyAVLTree::rightBalance(treeNode& node)
{
	//右边不平衡  需要左旋转
	if (get_Node_Banlance(node->rChild) > 0)
	{
		rl_Rotate(node);
	}
	else
	{
		ll_Rotate(node);
	}
}

treeNode MyAVLTree::insertAVLNode(treeNode& root,int val)
{
	if (root == NULL)
	{
		root = new TreeAVLNode(val);
		update_depth(root);
		return root;
	}
	treeNode tmep = NULL;
	if (val < root->val)
	{
		tmep = insertAVLNode(root->lChild, val);
	}
	else if (val > root->val)
	{
		tmep = insertAVLNode(root->rChild, val);
	}

	if (tmep)
	{
		AVLTree(root);
	}

	return tmep;
}

treeNode MyAVLTree::deleteAVLNode(treeNode& root, int val)
{
	if (root == NULL)
	{
		return NULL;
	}
	treeNode tmep = NULL;
	if (val < root->val)
	{
		tmep = deleteAVLNode(root->lChild, val);
	}
	else if (val > root->val)
	{
		tmep = deleteAVLNode(root->rChild, val);
	}
	else
	{
		return removeNodeForAVL(root);
	}

	if (tmep)
	{
		AVLTree(root);
	}

	return tmep;
}

treeNode MyAVLTree::removeNodeForAVL(treeNode& node)
{
	treeNode pCur;
	treeNode pNext;
	pCur = node;

	if (pCur->rChild == NULL)
	{
		node = pCur->lChild;
		return pCur;
	}
	else if (pCur->lChild == NULL)
	{
		node = pCur->rChild;
		return pCur;
	}
	else
	{
		pNext = pCur->lChild;
		while (pNext->rChild)
		{
			pCur = pNext;
			pNext = pNext->rChild;
		}
		node->val = pNext->val;
		if (pCur != node)
		{
			pCur->rChild = pNext->lChild;
		}
		else
		{
			pCur->lChild = pNext->lChild;
		}
		return pNext;
	}

	return NULL;
}

void levelOrder(vector<vector<int>> &ret, treeNode root, int level)
{
	if (root == NULL) return;

	if ((int)ret.size() <= level)
	{
		ret.push_back(vector<int>());
	}

	ret[level].push_back(root->val);

	levelOrder(ret, root->lChild, level + 1);
	levelOrder(ret, root->rChild, level + 1);
}

void MyAVLTree::printfTreeByarrangement()
{
	vector<vector<int>> ret;
	levelOrder(ret, m_Root, 0);

	for (auto arrs : ret)
	{
		for (auto i : arrs)
		{
			printf("%d ", i);
		}
		printf("\n");
	}
}

test.cpp

#include"AVLTree.h"

void test()
{
	MyAVLTree mytree;

	int sum[] = { 3,2,1,4,5,6,7,10,8,9 ,23,56,82,11,13,11,13,145,13,23,4,34,23,52,41,42,48,45,40};

	for (auto i : sum)
	{
		mytree.insertNode(i);
	}
	mytree.printfTreeByarrangement();
	for (auto i : sum)
	{
		if (mytree.deleteNode(i))
		{
			mytree.printfTreeByarrangement();
			printf("\n");
		}
	}
}

int main()
{
	test();
	getchar();
	return 0;
}

测试结果

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值