二叉搜索树及AVL平衡二叉搜索树

二叉搜索树

二叉搜索树是二叉树的的一种,只不过多了个限制条件,即左子树节点的值都小于该点,右子树节点的值都大于该点。

定义:

// 树节点
template <typename T>
class Node
{
public:
	T key;
	Node* parent;
	Node* left;
	Node* right;
	
	Node(T k, Node* p = nullptr, Node* l = nullptr, Node* r = nullptr) :
		key(k), parent(p), left(l), right(r) {}
};

// 二叉搜索树
template <typename T>
class BSTree
{
private:
	Node<T>* root_;
public:
	BSTree();
	~BSTree();

	Node<T>* Search(T key);
	Node<T>* Insert(T key);
	void Remove(T key);
private:
	void Destroy(Node<T>* &head);
};

这里只实现了最关键的三个操作:查找、插入和删除。

查找自然不必多说,类似于二分查找,从根节点开始判断往左往右还是命中。
插入也简单,类似查找,找到要插入的位置即可,注意新插入的节点必为叶子节点。

删除节点就麻烦一些了,需要分情况进行处理。
(1)删除的节点为叶子节点,直接删除即可。
《二叉搜索树及AVL平衡二叉搜索树》
(2)删除的节点只有一个孩子,把这个孩子提上来代替自己即可。
《二叉搜索树及AVL平衡二叉搜索树》
(3)删除的节点左右孩子皆有,这种情况需要先找到右子树最左节点,然后把这个节点跟要删除的节点交换,这样就变成了删除右子树最左节点了,而该最左节点必定无左孩子,这样删除就变成上面两种情况之一了。
《二叉搜索树及AVL平衡二叉搜索树》

这里还要注意的一点是当删除的节点为根节点时,要维护好根节点的更新。

实现:

template <typename T>
BSTree<T>::BSTree() : root_(nullptr) {}

template <typename T>
BSTree<T>::~BSTree()
{
	Destroy(root_);
}

template <typename T>
Node<T>* BSTree<T>::Search(T key)
{
	Node<T>* cur = root_;
	while (cur && cur->key != key)
	{
		if (key < cur->key)
			cur = cur->left;
		else
			cur = cur->right;
	}
	return cur;
}

template <typename T>
Node<T>* BSTree<T>::Insert(T key)
{
	Node<T>* cur = root_;
	Node<T>* pre = nullptr;

	// 找到插入位置
	while (cur)
	{
		pre = cur;
		if (key == cur->key)
			return cur;
		else if (key < cur->key)
			cur = cur->left;
		else
			cur = cur->right;
	}

	Node<T>* new_node = new Node<T>(key);
	new_node->parent = pre;
	// 插入为根节点
	if (pre == nullptr)
		root_ = new_node;
	// 插入为左孩子
	else if (key < pre->key)
		pre->left = new_node;
	// 插入为右孩子
	else
		pre->right = new_node;
}

template <typename T>
void BSTree<T>::Remove(T key)
{
	Node<T>* remove;
	// 不存在该节点
	if ((remove = Search(key)) == nullptr)
		return;

	// 为叶子节点,直接删除
	if (remove->left == nullptr && remove->left == nullptr)
	{
		if (remove->parent == nullptr) // 删除节点为根节点的情况
			root_ = nullptr;
		else if (remove->parent->left == remove)
			remove->parent->left = nullptr;
		else
			remove->parent->right = nullptr;
		delete remove;
		return;
	}

	// 左孩子为空,直接把右孩子提上来后删除自己
	if (remove->left == nullptr)
	{
		if (remove->parent == nullptr)
		{
			remove->right->parent = nullptr;
			root_ = remove->right;
		}
		else if (remove->parent->left == remove)
		{
			remove->right->parent = remove->parent;
			remove->parent->left = remove->right;
		}
		else
		{
			remove->right->parent = remove->parent;
			remove->parent->right = remove->right;
		}
		delete remove;
		return;
	}

	// 右孩子为空,直接把左孩子提上来后删除自己
	if (remove->right == nullptr)
	{
		if (remove->parent == nullptr)
		{
			remove->left->parent = nullptr;
			root_ = remove->left;
		}
		else if (remove->parent->left == remove)
		{
			remove->left->parent = remove->parent;
			remove->parent->left = remove->left;
		}
		else
		{
			remove->left->parent = remove->parent;
			remove->parent->right = remove->left;
		}
		delete remove;
		return;
	}

	// 左右孩子均不为空的情况,把该节点跟右子树最小节点交换后,转换为删除右子树最小节点
	Node<T>* right_min = remove->right;
	while (right_min->left) // 找到右子树最小节点
	{
		right_min = right_min->left;
	}
	remove->key = right_min->key; // 与要删除的节点交换
	if (right_min->right) // 有右孩子,转换为第三种情况
	{
		right_min->right->parent = right_min->parent;
		right_min->parent->left = right_min->right;
	}
	else // 无右孩子,转换为第二种情况
	{
		if (right_min->parent->left == right_min)
			right_min->parent->left = nullptr;
		else
			right_min->parent->right = nullptr;
	}
	delete right_min;
	return;
}

template <typename T>
void BSTree<T>::Destroy(Node<T>* &head)
{
	if (head == nullptr)
		return;
	if (head->left)
		Destroy(head->left);
	if (head->right)
		Destroy(head->right);

	delete head;
	head = nullptr;
}

AVL 自平衡二叉搜索树

AVL树在二叉搜索树的基础上加了平衡的限制条件,即对于每个节点,左右子树的高度差不能超过1,这样对于某些情况,该搜索树的性能就不至于下降。

AVL树的定义于普通的二叉搜索树大同小异,不过受限于平衡条件,插入和删除节点的操作就变得复杂起来,在每次插入或删除节点后,都要判断是否失衡并恢复平衡。

定义:

template <typename T>
class Node
{
public:
	T key;
	int height;
	Node* left;
	Node* right;
	
	Node(T k, Node* l = nullptr, Node* r = nullptr) :
		key(k), height(0), left(l), right(r) {}
};

template <typename T>
class AVLTree
{
private:
	Node<T>* root_;
public:
	AVLTree();
	~AVLTree();

	int Height(Node<T>* head);

	Node<T>* Search(T key);
	void Insert(T key);
	void Remove(T key);
private:
	Node<T>* LLRotation(Node<T>* head);
	Node<T>* RRRotation(Node<T>* head);
	Node<T>* LRRotation(Node<T>* head);
	Node<T>* RLRotation(Node<T>* head);

	Node<T>* Insert(Node<T>* &head, T key);
	Node<T>* Remove(Node<T>* &head, Node<T>* r);

	void Destroy(Node<T>* &head);
};

四种失衡状态及其恢复

(1)LL

《二叉搜索树及AVL平衡二叉搜索树》

(2)RR

《二叉搜索树及AVL平衡二叉搜索树》

(3)LR

《二叉搜索树及AVL平衡二叉搜索树》

(4)RL

《二叉搜索树及AVL平衡二叉搜索树》

有了四种失衡情况调整后就可以实现插入、删除了,这里插入删除都是用递归来写,比如插入,判断要往左子树还是右子树插入,递归下去,返回时就要判断左右子树是否出现了失衡,如果出现就判断是哪种情况并进行处理。

实现:

template <typename T>
AVLTree<T>::AVLTree() : root_(nullptr) {}

template <typename T>
AVLTree<T>::~AVLTree()
{
	Destroy(root_);
}

template <typename T>
int AVLTree<T>::Height(Node<T>* head)
{
	if (head)
		return head->height;
	return -1;
}

template <typename T>
Node<T>* AVLTree<T>::Search(T key)
{
	Node<T>* cur = root_;
	while (cur && cur->key != key)
	{
		if (key < cur->key)
			cur = cur->left;
		else
			cur = cur->right;
	}
	return cur;
}

template <typename T>
Node<T>* AVLTree<T>::LLRotation(Node<T>* head)
{
	Node<T>* tmp = head->left;
	head->left = tmp->right;
	tmp->right = head;

	head->height = max(Height(head->left), Height(head->right)) + 1;
	tmp->height = max(Height(tmp->left), Height(tmp->right)) + 1;

	return tmp;
}

template <typename T>
Node<T>* AVLTree<T>::RRRotation(Node<T>* head)
{
	Node<T>* tmp = head->right;
	head->right = tmp->left;
	tmp->left = head;

	head->height = max(Height(head->left), Height(head->right)) + 1;
	tmp->height = max(Height(tmp->left), Height(tmp->right)) + 1;

	return tmp;
}

template <typename T>
Node<T>* AVLTree<T>::LRRotation(Node<T>* head)
{
	head->left = RRRotation(head->left);
	return LLRotation(head);
}

template <typename T>
Node<T>* AVLTree<T>::RLRotation(Node<T>* head)
{
	head->right = LLRotation(head->right);
	return RRRotation(head);
}

template <typename T>
Node<T>* AVLTree<T>::Insert(Node<T>* &head, T key)
{
	// 插入为根节点
	if (head == nullptr)
	{
		head = new Node<T>(key);
	}
	// 往左子树插入
	else if (key < head->key)
	{
		head->left = Insert(head->left, key);
		// 判断是否失衡
		if (Height(head->left) - Height(head->right) == 2)
		{
			if (key < head->left->key)
				head = LLRotation(head);
			else
				head = LRRotation(head);
		}
	}
	// 往右子树插入
	else if (key > head->key)
	{
		head->right = Insert(head->right, key);
		if (Height(head->right) - Height(head->left) == 2)
		{
			if (key > head->right->key)
				head = RRRotation(head);
			else
				head = RLRotation(head);
		}
	}

	// 更新高度
	head->height = max(Height(head->left), Height(head->right)) + 1;
	// 返回插入后的根节点
	return head;
}

template <typename T>
void AVLTree<T>::Insert(T key)
{
	Insert(root_, key);
}

template <typename T>
Node<T>* AVLTree<T>::Remove(Node<T>* &head, Node<T>* r)
{
	// 找不到要删除的节点
	if (head == nullptr || r == nullptr)
		return nullptr;

	// 待删除的节点在左子树中
	if (r->key < head->key)
	{
		head->left = Remove(head->left, r);
		// 判断是否失衡
		if (Height(head->right) - Height(head->left) == 2)
		{
			if (Height(head->right->left) > Height(head->right->right))
				head = RLRotation(head);
			else
				head = RRRotation(head);
		}
	}
	// 待删除的节点在右子树中
	else if (r->key > head->key)
	{
		head->right = Remove(head->right, r);
		if (Height(head->left) - Height(head->right) == 2)
		{
			if (Height(head->left->left) > Height(head->left->right))
				head = LLRotation(head);
			else
				head = LRRotation(head);
		}
	}
	// head对应的节点就是要删除的节点
	else
	{
		// head的左右孩子皆非空
		if (head->left != nullptr && head->right != nullptr)
		{
			// 在左右子树高度较高者中找到最右或最左节点,与head交换,然后转为删除该节点
			// 删除策略与二叉搜索树一致
			// 在高度较高的子树中删除不会破坏平衡条件
			if (Height(head->left) > Height(head->right))
			{
				Node<T>* cur = head->left;
				while (cur->right)
					cur = cur->right;
				head->key = cur->key;
				head->left = Remove(head->left, cur);
			}
			else
			{
				Node<T>* cur = head->right;
				while (cur->left)
					cur = cur->left;
				head->key = cur->key;
				head->right = Remove(head->right, cur);
			}
		}
		// 有一个空节点或者为叶子节点
		else
		{
			Node<T>* tmp = head;
			head = head->left != nullptr ? head->left : head->right;
			delete tmp;
		}
	}
	// 返回删除后的根节点
	return head;
}

template <typename T>
void AVLTree<T>::Remove(T key)
{
	Node<T>* r = Search(key);
	if (r)
	{
		root_ = Remove(root_, r);
	}
}

template <typename T>
void AVLTree<T>::Destroy(Node<T>* &head)
{
	if (head == nullptr)
		return;
	if (head->left)
		Destroy(head->left);
	if (head->right)
		Destroy(head->right);

	delete head;
	head = nullptr;
}
    原文作者:平衡二叉树
    原文地址: https://blog.csdn.net/silence1772/article/details/83756909
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞