AVL树详解与总结

那年仲夏 提交于 2019-11-29 21:10:49

前言:

什么叫做AVL树?

    AVL树的定义:

1、AVL的左右子树高度之差的绝对值不超过1;

2、树中的左右子树都为AVL树

3、平衡因子只能是(-1、0、1)

    AVL树的效率

AVL树的总共节点为N个,他的高度能搞保持在logN,插入、删除、查找等操作的时间复杂度也是logN。


    AVL树的实现:

1、AVL树的插入:

思路分析:1> 既然是插入就需要先找到插入的位置,使用while循环遍历找到插入位置

                   2> 找到插入位置以后直接插入,然后向上遍历修改父节点的平衡因子,当修改完以后的平衡因子有等于2或者-2的挑出来,进行树的旋转,并且调整平衡因子,使满足AVL树的定义。

                   3> 旋转过程中需要考虑是左旋转、右旋转、左右旋转、还是右左旋转。左右旋转简单,直接调用自己编写的左右旋转函数即可,只要传过来的节点记得加上引用就行了,这样能够直接连接到旋转后的子树。重点在于左右和右左旋转,我们是否能直接调用左旋转函数和右旋转函数各一次?答案是否定的,因为在旋转的过程中,不是在插入的那个位置进行旋转,而是在中间进行旋转,这是后父亲节点和祖父节点的平衡因子BF就需要自己手动来定义了。以右左旋转来分析:

如果当前节点的平衡因子为-1,那么他的parent应该为1,pparent应该为0;

如果当前节点的平衡因子为1,那么他的parent应该为0,pparent应该为-1;

如果当前节点的平衡因子为0,那么他的parent应该为0,pparent应该为0;

具体自己下去画个图,在插入节点的位置(cur)下面加一个左节点或者右节点,然后分析。

#ifndef __BALANCETREE_H__
#define __BALANCETREE_H__

template<class K,class V>
struct BLNode
{
	K _key;
	V _value;
	BLNode<K, V>* _left;
	BLNode<K, V>* _right;
	BLNode<K, V>* _parent;
	int _bf;

	BLNode(const K& key, const V& value)
		:_key(key)
		, _value(value)
		, _parent(NULL)
		, _left(NULL)
		, _right(NULL)
		, _bf(0)
	{}

};

template<class K,class V>
class BalanceTree
{
	typedef BLNode<K, V> Node;

public:
	BalanceTree()
		:_root(NULL)
	{}

	bool Insert(const K& key, const V& value)
	{
		//先查找需要插入的位置
		if (_root == NULL)
		{
			_root = new Node(key, value);
			return true;
		}

		Node* parent = NULL;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}

		//找到插入位置以后,确定平衡因子
		Node* ppNode = parent->_parent;
		

		if (parent->_key > key)//找到插入位置以后判断是在父节点的左边还是右边,插入以后先调整平衡因子,向上遍历,如果本来是-1或者1插入以后为0就不用调整了,因为上一层看到的还是这一层的高度没有变
		{
			cur = new Node(key, value);
			parent->_left = cur;
			cur->_parent = parent;
			parent->_bf--;
			while (parent)
			{
				if ((parent->_bf == -1 ||parent->_bf ==1)&& parent->_parent != NULL)
				{
					if (parent->_parent->_key >parent->_key)
						parent->_parent->_bf--;
					else if (parent->_parent->_key < parent->_key)
						parent->_parent->_bf++;
					if (parent->_parent->_bf == 2 || parent->_parent->_bf == -2)
						break;
					cur = parent;
					parent = parent->_parent;
				}
				else
					break;
			}
			
		}

		else if (parent->_key < key)
		{
			cur = new Node(key, value);
			parent->_right = cur;
			cur->_parent = parent;
			parent->_bf++;
			while (parent)
			{
				if ((parent->_bf == 1 ||parent->_bf == -1)&& parent->_parent != NULL)
				{
					if (parent->_parent->_key >parent->_key)
						parent->_parent->_bf--;
					else if (parent->_parent->_key < parent->_key)
						parent->_parent->_bf++;
					if (parent->_parent->_bf == 2 || parent->_parent->_bf == -2)
						break;
					cur = parent;
					parent = parent->_parent;
				}
				else
					break;
			}
		}

		//根据平衡因子的变动,开始调整当前的树,因为刚刚是平衡因子不符合的时候跳出来的
		ppNode = parent->_parent;
		Node* pppNode = NULL;
		if (ppNode!=NULL)
			pppNode = ppNode->_parent;
		if (ppNode && (ppNode->_bf == 2 || ppNode->_bf == -2))
		{
			//左旋
			if (parent == ppNode->_right && parent->_right == cur)
			{
				RotateL(ppNode);
			}

			//右旋
			else if (ppNode->_left == parent && parent->_left == cur)
			{
				RotateR(ppNode);
			}

			//左右双旋
			else if (ppNode->_left == parent &&parent->_right == cur)
			{
				int bf = cur->_bf;
				Node* pNode = ppNode;
				Node* pLeftNode = parent;
				RotateL(parent);//先左旋,再链接
				ppNode->_left = parent;
				RotateR(ppNode);

				if (bf == 0)
				{
					pNode->_bf = 0;
					pLeftNode->_bf = 0;
				}
				else if (bf == -1)
				{
					pNode->_bf = 1;
					pLeftNode->_bf = 0;
				}
				else if (bf == 1)
				{
					pNode->_bf = 0;
					pLeftNode->_bf = -1;
				}
			}

			//右左双旋
			else if (ppNode->_right == parent &&parent->_left == cur)
			{
				int bf = cur->_bf;
				Node* pNode = ppNode;
				Node* pRightNode = parent;
				RotateR(parent);
				ppNode->_right = parent;
				RotateL(ppNode);

				if (bf == 0)
				{
					pNode->_bf = 0;
					pRightNode->_bf = 0;
				}
				else if (bf == -1)
				{
					pNode->_bf = 0;
					pRightNode->_bf = 1;
				}
				else if (bf == 1)
				{
					pNode->_bf = -1;
					pRightNode->_bf = 0;
				}
			}

			if (pppNode == NULL)
			{
				_root = ppNode;
			}
			else
			{
				if (pppNode->_key > ppNode->_key)
					pppNode->_left = ppNode;
				else if (pppNode->_key < ppNode->_key)
					pppNode->_right = ppNode;
			}

		}
	}


	size_t Height()
	{
		return _Height(_root);
	}
	
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

protected:
	size_t _Height(Node* root)
	{
		if (root == NULL)
			return 0;

		return _Height(root->_left) > _Height(root->_right) ? _Height(root->_left) + 1 : _Height(root->_right) + 1;
	}
	void _InOrder(Node* root)
	{
		if (root == NULL)
			return;

		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}

	void rotateL(Node*& parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		subR->_parent = parent->_parent;
		subR->_left = parent;
		parent->_parent = subR;

		parent->_right = subRL;
		if (subRL != NULL)
			subRL->_parent = parent;

		parent->_bf = 0;
		subR->_bf = 0;

		parent = subR;
	}

	void RotateL(Node*& parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;
		if (subRL != NULL)
			subRL->_parent = parent;

		subR->_parent = parent->_parent;
		parent->_parent = subR;
		subR->_left = parent;

		parent->_bf = 0;
		subR->_bf = 0;

		parent = subR;
	}

	void RotateR(Node*& parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		if (subLR != NULL)
			subLR->_parent = parent;

		subL->_parent = parent->_parent;
		subL->_right = parent;
		parent->_parent = subL;
		parent->_bf = 0;
		subL->_bf = 0;

		parent = subL;
	}



protected:
	Node* _root;
};




void test()
{
	BalanceTree<int, int> bt;
	int arr[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		bt.Insert(arr[i], i);
	}

	bt.InOrder();
	cout << bt.Height() << endl;

	BalanceTree<int, int> bt1;
	int arr1[] = { 4,2,6,1,3,5,15,7,16,14 };
	for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
	{
		bt1.Insert(arr1[i], i);
	}

	bt1.InOrder();
	cout << bt1.Height() << endl;
}


#endif //__BALANCETREE_H__

2、AVL树的删除:

    删除相对而言跟插入差不多,都是需要理解过程的,对于删除,我们只需要先找到要删除的位置,然后分为三种情况:

1.左为空-------->直接连接到父节点上,只是需要判断连接到父节点的左还是右上

2.右为空-------->同上

3.左右都不为空:找到右边子树的最左节点,(这里还分为两种情况:没有左子节点和有)这里只分析有左子节点的了,一直往左遍历找到左子节点,交换左子节点和要删除的节点,然后将parent->left连到左子节点的右就行了,最后一步就是调节平衡因子了,从当前节点开始向上修改平衡因子,以及判断平衡因子有没有为2或者-2的情况,然后跟上面一样做处理。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!