1. 程式人生 > >AVL樹(高度平衡的二叉搜尋樹)平衡因子的調節和旋轉

AVL樹(高度平衡的二叉搜尋樹)平衡因子的調節和旋轉

1.什麼叫AVL樹?

                   AVL樹又稱為高度平衡的二叉搜尋樹,它能保持二叉樹的高度平衡,儘量降低二叉樹的高度,減少樹的平均搜尋長度(儘量使這棵樹保持為完全二叉樹,這樣就能提高搜尋效率)。

2.AVL樹的性質

(1)左子樹和右子樹的高度之差的絕對值不超過1

          (2) 樹中的每個左子樹和右子樹都是AVL樹  

          (3) 每個節點都有一個平衡因子(balance factor--bf),任一節點的平衡因子是-1,0,1。(每個節點的平衡因子等於右子樹的高度減去左子  樹的高度)


3.AVL樹節點的定義
template <typename K,typename V>
struct AVLTreeNode
{
	K _key;
	V _value;
	int _bf; //平衡因子,只能取值為-1,1,0
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;
	AVLTreeNode(const K& key, const V& value)
		:_key(key)
		, _value(value)
		, _bf(0)
		, _left(NULL)
		, _right(NULL)
		, _parent(NULL)
	{}
};

4.AVL樹左單旋的情況
對應程式碼實現:
void _RotateL(Node* &parent)
	{
		//1.將要修改的結點標記起來
		Node* SubR = parent->_right;
		Node* SubRL = SubR->_left;
		Node* pparent = parent->_parent;
		//2.重新鏈上SubR結點
		SubR->_left = parent;
		SubR->_parent = pparent;
		SubR->_bf = 0;
		//4.重新鏈上parent結點
		parent->_right = SubRL;
		parent->_parent = SubR;
		parent->_bf = 0;
		//5.改變pparent的指向結點
		if (pparent == NULL)
			_root = SubR;
		else if (pparent->_left == parent)
			pparent->_left = SubR;
		else
			pparent->_right = SubR;
		//4.重新鏈上SubRL結點
		if (SubRL != NULL)
			SubRL->_parent = parent;
		
	}


5.AVL樹右單旋的情況
對應的程式碼實現:
	void _RotateR(Node* &parent)
	{
		//1.將要修改的結點標記起來
		Node* SubL = parent->_left;
		Node* SubLR = SubL->_right;
		Node* pparent = parent->_parent;
		//2.重新鏈上SubL結點
		SubL->_right = parent;
		SubL->_parent = parent->_parent;
		SubL->_bf = 0;
		//3.重新鏈上parent結點
		parent->_left = SubLR;
		parent->_parent = SubL;
		parent->_bf = 0;
		//4.改變pparent的指向結點
		if (pparent == NULL)
			_root = SubL;
		else if (pparent->_left == parent)
			pparent->_left = SubL;
		else
			pparent->_right = SubL;
		//5.重新鏈上SubRL結點
		if (SubLR != NULL)
			SubLR->_parent = parent;
	}


6.AVL樹平衡因子的調節      (1)插入的資料只能影響祖先結點的平衡因子;      (2)當某個平衡因子從0變成1或者-1,需要繼續調整祖先結點的平衡因子,直到根節點;      (3)當某個平衡因子從-1或者1變成0,則不需要調整祖先的平衡因子了,因為平衡因子在插入資料之後變成0,證明整棵樹的高度沒有發生變化;
     (4)當平衡因子在插入資料之後變成-2或者2,需要通過旋轉來降低它的高度,使它繼續保持AVL樹的性質 7.AVL樹進行左右雙旋的情況(注意平衡因子的調節
程式碼實現:
	void _RotateLR(Node* &parent)
	{
		//雙旋的時候在某些情況下會導致bf發生異常
		Node* SubL = parent->_left;
		Node* SubLR = SubL->_right;
		int bf = SubLR->_bf;
		_RotateL(parent->_left);
		_RotateR(parent);
		if (bf == -1)
		{
			parent->_bf = 1;
			SubL->_bf = 0;
		}
		else if (bf == 1)
		{
			parent->_bf = 0;
			SubL->_bf = -1;
		}
		else
		{
			SubL->_bf = parent->_bf = 0;
		}
		SubLR->_bf = 0;
	}

8.同樣的方法可以得到右左雙旋時平衡因子的變化
                  (1)SubRL->_bf==0   parent->_bf=SubR->_bf=0;   (2)SubRL->_bf==-1  parent->_bf=0  SubR->_bf=1; (3)SubRL->_bf==1   parent->_bf=-1 SubR->_bf=0; 程式碼實現:
	void _RotateRL(Node* &parent)
	{
		Node* SubR = parent->_right;
		Node* SubRL = SubR->_left;
		int bf = SubRL->_bf;
		_RotateR(parent->_right);
		_RotateL(parent);
		if (bf == 1)
		{
			parent->_bf = -1;
			SubR->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 0;
			SubR->_bf = 1;
		}
		else
		{
			SubR->_bf = parent->_bf = 0;
		}
		SubRL->_bf = 0;
	}