数据结构: AVL树

目录

1.AVL树的概念

2.AVL树的模拟实现

AVL树的结构定义

插入

对平衡因子的讨论

旋转

对旋转情况的讨论

1.单旋

1.1左单旋

1.2右单旋

2.双旋

2.1左右双旋

2.2右左双旋

检查是否是AVL树


1.AVL树的概念

当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度

一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:

  • 它的左右子树都是AVL树
  • 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)

数据结构: AVL树_第1张图片

2.AVL树的模拟实现

AVL树的结构定义

节点

​​​​​​​​​​​​​​数据结构: AVL树_第2张图片

AVLTree

数据结构: AVL树_第3张图片

插入

    插入节点会影响祖先(全部或者部分) ==>  需要更新平衡因子 ==> 讨论是否调整

    新增节点的位置进行讨论:

  1. cur == parent->right parent->bf++
  2. cur == parent->left parent->bf--

什么决定了是否要继续往上更新爷爷节点, 取决于parent所在的子树高度是否变化? 变了继续更新, 不变则不再更新

  • a. parent->bf == 1 || parent->bf == -1 parent所在的子树变了.继续更新, 为什么?        ==> 说明插入前parent->bf == 0 , 说明两边高度相等, 现在有一边高1, 说明parent的子一边高一边低, 高度变了.
  • b. parent->bf ==2 || parent == -2 -> parent所在的子树不平衡了, 需要处理子树(旋转处理)
  • c. parent->bf == 0, parent所在的子树高度不变, 不用继续往上更新, 这一次插入结束. 为什么?                                                                                                                                  ==> 说明插入前parent->bf == 1 or -1 ,说明插入之前一边高一边低, 插入节点填上矮的一边, 它的高度不变.

代码(找到插入的位置):

数据结构: AVL树_第4张图片

对平衡因子的讨论

数据结构: AVL树_第5张图片

旋转

目的: 1.让子树平衡 2. 降低子树的高度

旋转的原则: 保持它继续是搜索树

对旋转情况的讨论

1.单旋

--细节:

--空节点的处理

--parent需要维护(对parent是否是根节点进行讨论) 处理subR/L

--平衡因子更新

数据结构: AVL树_第6张图片

1.1左单旋

parent->_bf == 2 && cur->_bf == 1

--旋转 ==> 处理parent ==>更新平衡因子(parent的parent需要讨论, 影响与subR/L的链接)

数据结构: AVL树_第7张图片

代码:

	// 左单旋
	void RotateL(Node* pParent) 
	{
		Node* subR = pParent->_pRight;
		Node* subRL = subR->_pLeft;
		Node* ppnode = pParent->_pParent;

		//旋转
		//把subR的左(subRL)给parent的右,parent变为subR的左,并处理它们的parent
		if (subRL) 	
			subRL->_pParent = pParent;
		pParent->_pRight = subRL;


		pParent->_pParent = subR;
		subR->_pLeft = pParent;

		if (pParent == _pRoot) //根节点
		{
			_pRoot = subR;
			subR->_pParent = nullptr;
		}
		else //非根节点
		{
			if (ppnode->_pLeft == pParent) 
			{
				ppnode->_pLeft = subR;
			}
			else //ppnode->_pRight == pParent
			{
				ppnode->_pRight == subR;
			}
			subR->_pParent = ppnode;
		}
		//更新平衡因子
		pParent->_bf = subR->_bf = 0;
	}

1.2右单旋

parent->_bf == -2 && cur->_bf == -1

数据结构: AVL树_第8张图片

代码:

	// 右单旋
	void RotateR(Node* pParent)
	{
		Node* subL = pParent->_pLeft;
		Node* subLR = subL->_pRight;
		Node* ppnode = pParent->_pParent;

		//旋转
		//把subL的右(subLR)给parent, parent变为subL的右边, 并处理它们的parent
		if (subLR) 
			subLR->_pParent = pParent;
		pParent->_pLeft = subLR;

		pParent->_pParent = subL;
		subL->_pRight = pParent;

		if (pParent == _pRoot) 
		{
			_pRoot = subL;
			subL->_pParent = nullptr;
		}
		else 
		{
			if (ppnode->_pLeft == pParent) 
			{
				ppnode->_pLeft = subL;
			}
			else 
			{
				ppnode->_pRight = subL;
			}
			subL->_pParent = ppnode;
		}
		//更新平衡因子
		subL->_bf = pParent->_bf = 0;
	}

2.双旋

--对单旋的复用 ==> 更新平衡因子

需要保存subRL/LR的平衡因子, 根据插入节点的位置, 进行更新

数据结构: AVL树_第9张图片

2.1左右双旋

数据结构: AVL树_第10张图片

代码:

	// 左右双旋
	void RotateLR(Node* pParent) 
	{
		Node* subL = pParent->_pLeft;
		Node* subLR = subL->_pRight;
		int bf = subLR->_bf;

		//旋转
		RotateL(pParent->_pLeft);
		RotateR(pParent);

		//更新平衡因子
		if (bf == -1) 
		{
			pParent->_bf = 1;
			subL->_bf = 0;
			subLR->_bf = 0;
		}
		else if (bf == 1) 
		{
			pParent->_bf = 0;
			subL->_bf = -1;
			subLR->_bf = 0;
		}
		else if (bf == 0) 
		{
			pParent->_bf = 0;
			subL->_bf = 0;
			subLR->_bf = 0;
		}
		else 
		{
			assert(false);
		}
	}

2.2右左双旋

parent -> bf = 2 && cur -> bf = -1

数据结构: AVL树_第11张图片

代码:

	// 右左双旋
	void RotateRL(Node* pParent) 
	{
		Node* subR = pParent->_pRight;
		Node* subRL = subR->_pLeft;
		int bf = subRL->_bf;
		//右旋
		RotateR(pParent->_pRight);
		RotateL(pParent);

		//讨论平衡因子的更新
		if (bf == -1) 
		{
			pParent->_bf = 0;
			subR->_bf = 1;
			subRL->_bf = 0;
		}
		else if (bf == 1) 
		{
			pParent->_bf = -1;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else if (bf == 0) 
		{
			pParent->_bf = 0;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else 
		{
			assert(false);
		}
	}

检查是否是AVL树

1.各子树的高度差是否<=1

2.平衡因子是否正确(右子树-左子树高度判断)

代码:

	// AVL树的验证
	bool IsAVLTree()
	{
		return _IsAVLTree(_pRoot);
	}


	 根据AVL树的概念验证pRoot是否为有效的AVL树
	bool _IsAVLTree(Node* pRoot) 
	{
		if (pRoot == nullptr)
			return true;

		//1.检查各子树的高度差是否小于1
		int left_h = _Height(pRoot->_pLeft);
		int right_h = _Height(pRoot->_pRight);

		if (right_h - left_h != pRoot->_bf) 
		{
			cout << "平衡因子异常" << endl;
		}

		if (abs(left_h - right_h) > 1)
			return false;

		return  _IsAVLTree(pRoot->_pLeft) && _IsAVLTree(pRoot->_pRight);
	}

	size_t _Height(Node* pRoot) 
	{
		if (pRoot == nullptr) 
		{
			return 0;
		}

		size_t left_h = _Height(pRoot->_pLeft) + 1;
		size_t right_h = _Height(pRoot->_pRight) + 1;

		return left_h > right_h ? left_h : right_h;
	}

效果:

1.正常情况:

数据结构: AVL树_第12张图片

2.屏蔽掉平衡因子的修改:

数据结构: AVL树_第13张图片

你可能感兴趣的:(数据结构,数据结构,算法)