C++/数据结构——AVL树的基本操作

AVL树

一.什么是AVL树?

AVL树本质上也是一棵二叉搜索树,不过它是一棵高度平衡的二叉搜索树

平衡二叉树:左右子树的高度差不超过1;

二.如何实现?

在二叉搜索树的前提上为每一个结点加入一个平衡因子成员变量,再加入一个指向父节点的指针变量;

平衡因子:右子树高度 - 左子树高度

三.旋转

1.右边的右边高--左单旋

2.左边的左边高--右单旋

3.左右双旋:

扫描二维码关注公众号,回复: 9542150 查看本文章

4.右左双旋:

四.实现

#include <iostream>
using namespace std;


//AVL树:二叉搜索平衡树
template <class T>
struct AVLNode {
	T _data;
	AVLNode<T>* _left;
	AVLNode<T>* _right;
	AVLNode<T>* _parent;
	int _bf;

	AVLNode(const T& data = T())
		:_data(data),
		_left(nullptr),
		_right(nullptr),
		_parent(nullptr),
		_bf(0)
	{}
};

template <class T>
class AVLTree {
public:
	typedef AVLNode<T> Node;
	typedef Node* pNode;

	AVLTree()
		:_root(nullptr)
	{}

	//查找
	pNode Find(const T& data) {
		//先判断树是否为空
		if (_root == nullptr) {
			return _root;
		}
		//树不为空,按照性质来查找
		pNode cur = _root;
		while (cur) {
			if (cur->_data == data) {
				break;
			}
			if (cur->_data > data) {
				cur = cur->_left;
			}
			else {
				cur = cur->_right;
			}
		}
		return cur;
	}

	//左边的左边高——右单旋
	void RotateRight(pNode node) {
		pNode subL = node->_left;
		pNode subLR = subL->_right;

		subL->_right = node;
		node->_left = subLR;

		//判断subLR是否存在
		if (subLR) {
			subLR->_parent = node;
		}

		//判断是否是根节点
		if (node != _root) {
			pNode parent = node->_parent;
			if (parent->_left == node) {
				parent->_left = subL;
			}
			else {
				parent->_right = subL;
			}
			subL->_parent = parent;
		}
		//不是根节点
		else {
			_root = subL;
			subL->_parent = nullptr;
		}
		node->_parent = subL;
		//更改平衡因子
		node->_bf = subL->_bf = 0;
	}

	//右边的右边高——左单旋
	void RotateLeft(pNode node) {
		pNode subR = node->_right;
		pNode subRL = subR->_left;

		node->_right = subRL;
		subR->_left = node;

		if (subRL) {
			subRL->_parent = node;
		}

		//判断是否是根节点
		if (node != _root) {
			pNode parent = node->_parent;
			if (parent->_left == node) {
				parent->_left = subR;
			}
			else {
				parent->_right = subR;
			}
			subR->_parent = parent;
		}
		//是根节点
		else {
			_root = subR;
			subR->_parent = nullptr;
		}
		node->_parent = subR;

		//更改平衡因子
		node->_bf = subR->_bf = 0;
	}


	//结点的插入
	bool Insert(const T& data) {
		//先判断树是否为空
		if (_root == nullptr) {
			_root = new Node(data);
			return true;
		}
		//树非空,根据二叉搜索树的性质找到合适的叶子位置
		pNode cur = _root;
		pNode parent = nullptr;
		while (cur) {
			//判断是否有相同的结点
			if (cur->_data == data) {
				cout << "存在相同节点!!!" << endl;
				return false;
			}
			parent = cur;
			if (cur->_data > data) {
				cur = cur->_left;
			}
			else {
				cur = cur->_right;
			}
		}
		//找到了合适的叶子结点的位置
		cur = new Node(data);
		if (parent->_data > cur->_data) {
			parent->_left = cur;
		}
		else {
			parent->_right = cur;
		}
		cur->_parent = parent;


		//结点插入完毕,开始进行调整
		//从叶子结点开始进行调整
		while (parent) {
			//在这里先更改平衡因子
			if (parent->_left == cur) {
				--parent->_bf;
			}
			else {
				++parent->_bf;
			}
			
			//开始判断是否需要旋转调整
			//如果父节点的平衡因子是0,表示对其父路径上的结点没有干扰,直接退出循环,调整完毕
			if (parent->_bf == 0) {
				break;
			}
			//如果父节点的平衡因子是1 / -1 ,则表明父节点的平衡因子的改变对其父路径上的结点已经有所影响,
			//需要向上检查其他节点是否平衡
			else if (parent->_bf == 1 || parent->_bf == -1) {
				cur = parent;
				parent = parent->_parent;
			}
			//左边的左边高——右单旋
			else if (parent->_bf == -2 && cur->_bf == -1) {
				RotateRight(parent);
				break;
			}
			//右边的右边高——左单旋
			else if (parent->_bf == 2 && cur->_bf == 1) {
				RotateLeft(parent);
				break;
			}
			//双旋的场景:
			//左边的右边高——先左旋,再右旋
			else if (parent->_bf == -2 && cur->_bf == 1) {
				pNode subLR = cur->_right;
				pNode subL = cur;
				RotateLeft(cur);
				RotateRight(parent);
				if (subLR->_bf == -1) {
					parent->_bf = 1;
					subL->_bf = 0;
				}
				else if (subLR->_bf == 1) {
					parent->_bf = 0;
					subL->_bf = -1;
				}
				break;
			}
			//右边的左边高——先右旋,再左旋
			else if(parent->_bf == 2 && cur->_bf == -1){
				pNode subR = cur;
				pNode subRL = cur->_left;
				RotateRight(cur);
				RotateLeft(parent);
				if (subRL->_bf == 1) {
					parent->_bf = -1;
					subR->_bf = 0;
				}
				else if (subRL->_bf == -1) {
					parent->_bf = 0;
					subR->_bf = 1;
				}
				break;
			}
		}
		return true;
	}

	//结点的删除
	void _inOrder(pNode root) {
		if (root == nullptr) {
			return;
		}
		_inOrder(root->_left);
		cout << root->_data << " ";
		_inOrder(root->_right);
	}

	void InOrder() {
		_inOrder(_root);
		cout << endl;
	}

	int height(pNode root) {
		if (root == nullptr) {
			return 0;
		}
		int left = height(root->_left);
		int right = height(root->_right);
		return left > right ? left + 1 : right + 1;
	}

	bool _isAVLTree(pNode root) {
		//判断每个结点的平衡因子与高度差是否相同
		if (root == nullptr) {
			return true;
		}
		int leftHeight = height(root->_left);
		int rightHeight = height(root->_right);
		int heightgap = rightHeight - leftHeight;
		if (root->_bf != heightgap || root->_bf > 1 || root->_bf < -1) {
			cout << root->_data << ":平衡因子-->" << root->_bf << endl;
			cout << "高度差:" << heightgap << endl;
			return false;
		}
		return _isAVLTree(root->_left) && _isAVLTree(root->_right);
	}

	bool IsAVLTree() {
		return _isAVLTree(_root);
	}

private:
	pNode _root;
};

void test() {
	AVLTree<int> avl;
	avl.Insert(5);
	avl.Insert(6);
	avl.Insert(7);
	avl.Insert(8);
	avl.Insert(9);
	avl.InOrder();
	cout << avl.IsAVLTree() << endl;
	avl.InOrder();
	cout << avl.IsAVLTree() << endl;

}

int main() {
	test();
	system("pause");
	return 0;
}
发布了58 篇原创文章 · 获赞 43 · 访问量 4395

猜你喜欢

转载自blog.csdn.net/Wz_still_shuai/article/details/100531529
今日推荐