談平衡二叉樹的原理(c++實現)


Self-Balancing Binary Search Tree

定義

任意節點子樹的高度差(稱為平衡因子)不超過1。

節點結構體:
template<class T>
struct Node {
	T key;
	Node<T>* lchild;
	Node<T>* rchild;
	Node<T>(T k) : key(k), lchild(nullptr), rchild(nullptr) {}
};
平衡二叉樹類:
template<class T>
class AVLTree {
private:
	Node<T>* root;
public:
	AVLTree() :root(nullptr) {};
	Node<T>* getRoot() { return root; }
	void printTree();
	Node<T>* llRotation(Node<T>*);
	Node<T>* lrRotation(Node<T>*);
	Node<T>* rrRotation(Node<T>*);
	Node<T>* rlRotation(Node<T>*);
	void balance(Node<T>*);
	void insert(const T&);
	bool remove(Node<T>*, Node<T>*, T);
	int getDepth(Node<T>*);
	int getBalanceFactor(Node<T>*);
	Node<T>* findMin(Node<T>*);
	Node<T>* findMax(Node<T>*);
	void fixUp();  //修復平衡
	Node<T>* find(Node<T>* node, T key);
};

操作

二叉平衡樹與二叉排序樹非常相似,以下重點談談樹的自平衡策略。

左旋的動態過程:

右旋的動態過程:

ll型(右旋)

插入或者刪除導致某節點a失衡(平衡因子絕對值大於1),而且a的左子樹b(a->lchild)的左子樹c(b->lchild)比右子樹d(b->rchild)高。對a節點作ll平衡

template<class T>
Node<T>* AVLTree<T>::llRotation(Node<T>* node) {  //插入節點在左子樹左邊,右旋
	Node<T>* temp = node->lchild;
	node->lchild = temp->rchild;
	temp->rchild = node;
	return temp;
}

lr型

插入或者刪除導致某節點a失衡(平衡因子絕對值大於1),而且a的左子樹b(a->lchild)的左子樹c(b->lchild)比右子樹d(b->rchild)矮。對b節點作rr平衡,再對a作ll平衡

template<class T>
Node<T>* AVLTree<T>::lrRotation(Node<T>* node) {  //插入節點在左子樹右邊
	Node<T>* temp = node->lchild;
	node->lchild = rrRotation(temp);
	return llRotation(node);
}

rr型

與ll型對稱

rl型

與lr型對稱

平衡策略

自頂向下查找失衡節點,根據平衡因子的情況作平衡處理。總體而言,是將節點從樹高的一側借調到樹低的一側。(如果Node中有parent指針的話可以自底向上,從插入或刪除節點開始尋找失衡節點)

template<class T>
void AVLTree<T>::balance(Node<T>* node) {
	int bf = getBalanceFactor(node);  //平衡因子
	if (bf > 1) {  //失衡,左高
		if (getBalanceFactor(node->lchild) > 0)  //左左高,ll
			root = llRotation(node);
		else  //左右高,lr
			root = lrRotation(node);
	}
	else if (bf < -1) {  //失衡,右高
		if (getBalanceFactor(node->rchild) > 0)  //右左高,rl
			root = rlRotation(node);
		else
			root = rrRotation(node);  //右邊高,rr
	}
	return;
}

源碼

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

template<class T>
struct Node {
	T key;
	Node<T>* lchild;
	Node<T>* rchild;
	Node<T>(T k) : key(k), lchild(nullptr), rchild(nullptr) {}
};

template<class T>
class AVLTree {
private:
	Node<T>* root;
public:
	AVLTree() :root(nullptr) {};
	Node<T>* getRoot() { return root; }
	void printTree();
	Node<T>* llRotation(Node<T>*);
	Node<T>* lrRotation(Node<T>*);
	Node<T>* rrRotation(Node<T>*);
	Node<T>* rlRotation(Node<T>*);
	void balance(Node<T>*);
	void insert(const T&);
	bool remove(Node<T>*, Node<T>*, T);
	int getDepth(Node<T>*);
	int getBalanceFactor(Node<T>*);
	Node<T>* findMin(Node<T>*);
	Node<T>* findMax(Node<T>*);
	void fixUp();
	Node<T>* find(Node<T>* node, T key);
};

template<class T>
void AVLTree<T>::printTree() {  //層次遍歷
	Node<T>* pos = root;  //當前位置
	Node<T>* flag = root;  //層末標識

	queue<Node<T>*> q;
	q.push(root);  //根節點入隊

	while (!q.empty()) {  //隊列非空
		Node<T>* node = q.front();
		q.pop();  //彈出隊首
		cout << node->key << '\t';

		if (node->lchild != nullptr) {  //左孩子非空則入隊
			q.push(node->lchild);
			pos = node->lchild;
		}

		if (node->rchild != nullptr) {  //右孩子非空則入隊
			q.push(node->rchild);
			pos = node->rchild;
		}

		if (node == flag) {  //抵達層末
			flag = pos;
			cout << "\n";
		}
	}
}

template<class T>
void AVLTree<T>::insert(const T& key) {
	Node<T>* node = new Node<T>(key);
	if (root == nullptr) {
		root = node;
		return;
	}
	Node<T>* pos = root;
	while (true) {  //查找插入位置
		if (node->key < pos->key) {
			if (pos->lchild == nullptr) {
				pos->lchild = node;
				fixUp();
				return;
			}   //end if
			else
				pos = pos->lchild;
		}  //end if
		else if (node->key > pos->key) {
			if (pos->rchild == nullptr) {
				pos->rchild = node;
				fixUp();
				return;
			}  //end if
			else
				pos = pos->rchild;
		}  //end if
		else
			return;  //樹中已有此節點則無操作
	}  //end while
}

template<class T>
int AVLTree<T>::getDepth(Node<T>* node) {
	if (node == nullptr)
		return 0;
	return max(getDepth(node->lchild), getDepth(node->rchild)) + 1;
}

template<class T>
int AVLTree<T>::getBalanceFactor(Node<T>* node) {  //平衡因子 = 左子樹高-右子樹高
	return getDepth(node->lchild) - getDepth(node->rchild);
}

template<class T>
void AVLTree<T>::balance(Node<T>* node) {
	int bf = getBalanceFactor(node);
	if (bf > 1) {
		if (getBalanceFactor(node->lchild) > 0)
			root = llRotation(node);
		else
			root = lrRotation(node);
	}
	else if (bf < -1) {
		if (getBalanceFactor(node->rchild) > 0)
			root = rlRotation(node);
		else
			root = rrRotation(node);
	}
	return;
}

template<class T>
Node<T>* AVLTree<T>::llRotation(Node<T>* node) {  //插入節點在左子樹左邊,右旋
	Node<T>* temp = node->lchild;
	node->lchild = temp->rchild;
	temp->rchild = node;
	return temp;
}

template<class T>
Node<T>* AVLTree<T>::lrRotation(Node<T>* node) {  //插入節點在左子樹右邊
	Node<T>* temp = node->lchild;
	node->lchild = rrRotation(temp);
	return llRotation(node);
}

template<class T>
Node<T>* AVLTree<T>::rlRotation(Node<T>* node) {  //插入節點在右子樹左邊
	Node<T>* temp = node->rchild;
	node->rchild = llRotation(temp);
	return rrRotation(node);
}

template<class T>
Node<T>* AVLTree<T>::rrRotation(Node<T>* node) {  //插入節點在右子樹左邊,左旋
	Node<T>* temp = node->rchild;
	node->rchild = temp->lchild;
	temp->lchild = node;
	return temp;
}

template<class T>
bool AVLTree<T>::remove(Node<T>* node, Node<T>* parent, T key) {
	Node<T>* temp = nullptr;
	if (node == nullptr)  // 未找到目標節點
		return false;
	else if (key < node->key)
		return remove(node->lchild, node, key);
	else if (key > node->key)
		return remove(node->rchild, node, key);
	else if (node->lchild && node->rchild) {  //刪除節點有左子樹也有右子樹

		if (getDepth(node->lchild) > getDepth(node->rchild)) {  //左子樹高,前驅替代
			temp = findMax(node->lchild);
			node->key = temp->key;
			return remove(node->lchild,node, node->key);
		}
		else {  //右子樹不比左子樹矮,后驅替代
			temp = findMin(node->rchild);
			node->key = temp->key;
			return remove(node->rchild, node, node->key);
		}
	}
	else {
		if ((node->lchild && node->rchild == nullptr)) {  //刪除節點有左孩子無右孩子
			temp = findMax(node->lchild);
			node->key = temp->key;
			return remove(node->lchild, node, node->key);
		}
		else if (node->rchild && node->lchild == nullptr) {  //刪除節點有右孩子無左孩子
			temp = findMin(node->rchild);
			node->key = temp->key;
			return remove(node->rchild, node, node->key);
		}  //end if
		else {  //刪除節點最終遞歸到刪除葉子節點
			if (node == parent->lchild)  //父節點指針置空
				parent->lchild = nullptr;
			else
				parent->rchild = nullptr;
			delete node;  //釋放子節點
			node = nullptr;

			fixUp();
		}
	}  //end else
	return true;
}

template<class T>
void AVLTree<T>::fixUp() {
	Node<T>* temp = this->root;  //自頂向下調整樹
	while (1)  //尋找失衡的節點
	{
		if (getBalanceFactor(temp) == 2) {
			if (fabs(getBalanceFactor(temp->lchild)) == 1)
				break;
			else
				temp = temp->lchild;
		}
		else if (getBalanceFactor(temp) == -2) {
			if (fabs(getBalanceFactor(temp->rchild)) == 1)
				break;
			else
				temp = temp->rchild;
		}
		else break;
	}
	balance(temp);
	return;
}

template<class T>
Node<T>* AVLTree<T>::find(Node<T>* node, T key) {
	while (node != nullptr && key != node->key) {  //迭代查找
		if (key < node->key)
			node = node->lchild;
		else
			node = node->rchild;
	}
	if (node == nullptr)
		cout << "Element " << key << " doesn't exist!" << endl;
	else
		cout << "Element " << key << " exists." << endl;
	return node;
}

template<class T>
Node<T>* AVLTree<T>::findMax(Node<T>* node) {
	if (node != nullptr) {
		while (node->rchild)
			node = node->rchild;
	}
	return node;
}

template<class T>
Node<T>* AVLTree<T>::findMin(Node<T>* node) {
	if (node != nullptr) {
		if (node->lchild == nullptr)  //左孩子為空,當前節點已是最左下
			return node;
		else
			return findMin(node->lchild);  //左孩子不為空,往左子樹遍歷
	}
	else
		return nullptr;  //空樹返回nullptr
}

int main() {
	int arr[]{ 7,4,8,5,1,6};//ll:738512建樹;rr:7385129刪除2;rl:7385124刪除4;lr:748516建樹
	AVLTree<int> avl;
	for (int i = 0; i < 6; i++)
	{
		avl.insert(arr[i]);
	}
	avl.printTree();
	avl.find(avl.getRoot(),8);
	avl.remove(avl.getRoot(), nullptr, 8);
	avl.printTree();
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM