AVL树的实现及测试

目录

1.AVL树的结构

2.AVL树节点的创建

3.insert(插入)的实现(部分)

4.关于AVL树的旋转问题

1)右单旋

2)左单旋

3)左右单旋

分几种情况去讨论旋转后的平衡因子调节:

第一种:

第二种:

第三种:

4)右左单旋

5.find查找功能

6. Is_balance判断是否平衡功能

7.测试

8.完整代码


1.AVL树的结构

二叉搜索树虽可以缩短查找的效率,但 如果数据有序或接近有序二叉搜索树将退化为单支树,查
找元素相当于在顺序表中搜索元素, 效率低下
为了解决上述问题,使得二叉搜索树的每个节点的左子树和右子树的高度差不大于1,因此就诞生了AVL树 ->   可降低树的高度,从而减少平均 搜索长度。
毋庸置疑,与完全二叉树的 高度一样,它的 搜索复杂度可达到惊人的 log2^n

2.AVL树节点的创建

首先要去清楚一下每个节点需要一些什么东西:

1)最重要的肯定是存储的数据

2)然后又因为是一颗树,肯定要包含左右指针指向左孩子和右孩子;

3)因为AVL树是平衡的,但是这种平衡是需要去维护的,因此还需要有平衡因子(我这里定义为右子树高度 - 左子树高度)以及父节点

这里我实现的AVL并不是一个完全泛型,而是用的一个key_value模型:

template<class K, class V>
struct AVLTreeNode
{
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;
	pair<K, V> _kv;

	int _bf;

	AVLTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _bf(0)
	{}
};

3.insert(插入)的实现(部分)

遵循二叉搜索树的结构去插入即可,即左孩子比根小,右孩子比根大

bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}

		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (kv.first < cur->_kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (kv.first > cur->_kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}

		cur = new Node(kv);
		if (parent->_kv.first > kv.first)
			parent->_left = cur;
		else
			parent->_right = cur;

		cur->_parent = parent;
}

但是这只是搜索二叉树的插入操作,这时AVL树,我们需要去调整它的平衡因子

如果插入在左边,则该节点的bf--,若在右边,则++:

            if (parent->_left == cur)
			{
				parent->_bf--;
			}
			else if (parent->_right == cur)
			{
				parent->_bf++;
			}

若parent->_bf == 0时,就不用再次向上调整,因为它 ++或者--之前 原本平衡因子是1或-1,变成0后不会影响祖先的平衡因子

若parent->_bf == 1 或 -1时,则需要继续往上更新,因为它 ++或者--之前 原本平衡因子是0(为什么不能是2 ? -> 因为在插入数据之前AVL树肯定是平衡的、已经调整过的),插入到哪边都会影响到祖先的平衡因子

若为 2 或 -2,则需要进行旋转处理,因为已经打破了规则

            if (parent->_bf == 0)
			{
				break;
			}
			else if (parent->_bf == 1 || parent->_bf == -1)
			{
				// 继续往上更新
				cur = parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == 2 || parent->_bf == -2) // 1 -1 -> 2 -2
			{
                ......
            }

4.关于AVL树的旋转问题

1)右单旋

这时,就会变成 ->

60的平衡因子就变成了-2,破坏了AVL的规则,需要旋转,如何旋转呢:

将30变成根,60变为30的右,30的右变为60的左 -> 这就是右单旋

条件: parent->_bf == -2, cur->_bf == -1

2)左单旋

在c的左或者右插入一个数:

->

30的平衡因子就变成了2,破坏了AVL的规则,需要旋转,如何旋转呢:

将60变成根,30变为60的左,60的左变为30的右 ->这就是左单旋

条件: parent->_bf == 2, cur->_bf == 1

3)左右单旋

这时在b或者c的子孩子位置插入数据,则会导致

90的平衡因子变为了-2,30的平衡因子变为了1

这个时候,单纯的右单旋是解决不了问题的,因为旋转之后还是会出现2这个平衡因子

这时候就需要先对30进行左单旋(将其变为右单旋的情况后),再对90进行右单旋

即RotateL(30), 然后RotateR(90),但是这样之后并没有完全解决,因为两个旋转叠加,导致平衡因子错乱,需要我们自己调整

分几种情况去讨论旋转后的平衡因子调节:

第一种:

在b处插入数据,导致60的平衡因子变为-1的:

使得parent->_bf = 1、subL->_bf = 0、subLR->_bf = 0。

第二种:

在c处插入数据,导致60的平衡因子变为1的:

使得parent->_bf = 0、subL->_bf = -1、subLR->_bf = 0。

第三种:

60即为将要新增的位置:

使得parent->_bf = 0、subL->_bf = 0、subLR->_bf = 0。

4)右左单旋

右左单旋与左右单旋极其相似:(这里就直接给结论了)

5.find查找功能

直接遵循搜索二叉树的规则进行查找即可

    Node* find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (key < cur->_kv.first)
			{
				cur = cur->_left;
			}
			else if (key > cur->_kv.first)
			{
				cur = cur->_right;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;
	}

6. Is_balance判断是否平衡功能

递归实现,学习过二叉树的应该简单:

    bool Is_balance()
	{
		return _Is_balance(_root);
	}
    bool _Is_balance(Node* root)
	{
		if (root == nullptr)
			return true;

		int LH = _Height(root->_left);
		int RH = _Height(root->_right);

		if (abs(LH - RH) >= 2)
			return false;

		if (RH - LH != root->_bf)
			return false;

		return _Is_balance(root->_left) && _Is_balance(root->_right);
	}

7.测试

Inorder只需要中序遍历一遍即可,这样就可以得到升序

void TestTree1()
{
	int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };

	AVLTree<int, int> a1;
	for (int e : a)
	{
		if (e == 4)
		{
			int i = 0;
		}
		a1.Insert({ e, e });

		cout << "插入值为" << e << "时,树是否平衡 - 》" << a1.Is_balance() << endl;
	}

	a1.Inorder();

}

8.完整代码

#pragma once
#include <iostream>
#include <vector>
#include <assert.h>

template<class K, class V>
struct AVLTreeNode
{
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;
	pair<K, V> _kv;

	int _bf;

	AVLTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _bf(0)
	{}
};

template<class K, class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
	void RotateR(Node* parent)
	{
		Node* ppNode = parent->_parent;
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

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

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

		if (parent == _root)
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subL;
			}
			else
			{
				ppNode->_right = subL;
			}

			subL->_parent = ppNode;
		}

		parent->_bf = subL->_bf = 0;
	}

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

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

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

		if (parent == _root)
		{
			_root = subR;
			_root->_parent = nullptr;
		}
		else
		{
			if (ppNode->_right == parent)
			{
				ppNode->_right = subR;
			}
			else
			{
				ppNode->_left = subR;
			}
			subR->_parent = ppNode;
		}

		subR->_bf = parent->_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)
		{
			subRL->_bf = 0;
			subR->_bf = 1;
			parent->_bf = 0;
		}
		else if (bf == 1)
		{
			subRL->_bf = 0;
			subR->_bf = 0;
			parent->_bf = -1;
		}
		else if (bf == 0)
		{
			subRL->_bf = 0;
			subR->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}

	void RotateLR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		int bf = subLR->_bf;

		RotateL(parent->_left);
		RotateR(parent);

		if (bf == -1)
		{
			subL->_bf = 0;
			subLR->_bf = 0;
			parent->_bf = 1;
		}
		else if (bf == 1)
		{
			subL->_bf = -1;
			subLR->_bf = 0;
			parent->_bf = 0;
		}
		else if (bf == 0)
		{
			subL->_bf = 0;
			subLR->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}

	bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}

		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (kv.first < cur->_kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (kv.first > cur->_kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}

		cur = new Node(kv);
		if (parent->_kv.first > kv.first)
			parent->_left = cur;
		else
			parent->_right = cur;

		cur->_parent = parent;

		// 更新平衡因子bf
		while (parent)
		{
			if (parent->_left == cur)
			{
				parent->_bf--;
			}
			else if (parent->_right == cur)
			{
				parent->_bf++;
			}

			if (parent->_bf == 0)
			{
				break;
			}
			else if (parent->_bf == 1 || parent->_bf == -1)
			{
				// 继续往上更新
				cur = parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == 2 || parent->_bf == -2) // 1 -1 -> 2 -2
			{
				// 当前子树出问题了,需要旋转平衡一下
				if (parent->_bf == -2 && cur->_bf == -1)
				{
					RotateR(parent);
				}
				else if (parent->_bf == 2 && cur->_bf == 1)
				{
					RotateL(parent);
				}
				else if (parent->_bf == 2 && cur->_bf == -1)
				{
					RotateRL(parent);
				}
				else if (parent->_bf == -2 && cur->_bf == 1)
				{
					RotateLR(parent);
				}
				else
				{
					// 理论而言不可能出现这个情况
					assert(false);
				}
				break;
			}
		}

		return true;
	}

	Node* find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (key < cur->_kv.first)
			{
				cur = cur->_left;
			}
			else if (key > cur->_kv.first)
			{
				cur = cur->_right;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;
	}

	void Inorder()
	{
		_Inorder(_root);
		cout << endl;
	}

	int Height()
	{
		return _Height(_root);
	}

	bool Is_balance()
	{
		return _Is_balance(_root);
	}

	int Size()
	{
		return _Size(_root);
	}

private:
	int _Size(Node* root)
	{
		return root == nullptr ? 0 : _Size(root->_left) + _Size(root->_right) + 1;
	}

	int _Height(Node* root)
	{
		if (root == nullptr)
			return 0;

		return max(_Height(root->_left), _Height(root->_right)) + 1;
	}

	bool _Is_balance(Node* root)
	{
		if (root == nullptr)
			return true;

		int LH = _Height(root->_left);
		int RH = _Height(root->_right);

		if (abs(LH - RH) >= 2)
			return false;

		if (RH - LH != root->_bf)
			return false;

		return _Is_balance(root->_left) && _Is_balance(root->_right);
	}

	void _Inorder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}

		_Inorder(root->_left);
		cout << root->_kv.first << ":" << root->_kv.second << endl;
		_Inorder(root->_right);
	}

	Node* _root = nullptr;
};

void TestTree1()
{
	int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };

	AVLTree<int, int> a1;
	for (int e : a)
	{
		if (e == 4)
		{
			int i = 0;
		}
		a1.Insert({ e, e });

		cout << "插入值为" << e << "时,树是否平衡 - 》" << a1.Is_balance() << endl;
	}

	a1.Inorder();

}

void TestTree2()
{
	const int N = 10000000;
	vector<int> v;
	v.reserve(N);
	srand(time(0));

	// 插入随机数
	for (size_t i = 0; i < N; i++)
	{
		v.push_back(rand() + i);
	}

	// 测试AVLTree插入速度
	size_t begin2 = clock();
	AVLTree<int, int> t;
	for (auto e : v)
	{
		t.Insert(make_pair(e, e));
	}
	size_t end2 = clock();
	cout << "Insert:" << end2 - begin2 << endl;

	cout << "Height:" << t.Height() << endl;
	cout << "Size:" << t.Size() << endl;

	// 测试ALVTree查找速度
	size_t begin1 = clock();
	for (auto e : v)
	{
		t.find(e);
	}
	size_t end1 = clock();
	cout << "Find:" << end1 - begin1 << endl;
}
  • 19
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AVL树是一种自平衡的二叉搜索树,它的升序遍历可以通过中序遍历来实现。下面是Java实现AVL树升序遍历的示例代码: ```java // AVL树节点定义 class Node { int key; int height; Node left; Node right; Node(int key) { this.key = key; this.height = 1; } } // AVL树类定义 class AVLTree { Node root; // 获取节点的高度 int getHeight(Node node) { if (node == null) { return 0; } return node.height; } // 更新节点的高度 void updateHeight(Node node) { node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1; } // 获取节点的平衡因子 int getBalanceFactor(Node node) { if (node == null) { return 0; } return getHeight(node.left) - getHeight(node.right); } // 右旋操作 Node rotateRight(Node y) { Node x = y.left; Node T2 = x.right; x.right = y; y.left = T2; updateHeight(y); updateHeight(x); return x; } // 左旋操作 Node rotateLeft(Node x) { Node y = x.right; Node T2 = y.left; y.left = x; x.right = T2; updateHeight(x); updateHeight(y); return y; } // 插入节点 Node insertNode(Node node, int key) { if (node == null) { return new Node(key); } if (key < node.key) { node.left = insertNode(node.left, key); } else if (key > node.key) { node.right = insertNode(node.right, key); } else { return node; // 不允许插入重复的节点 } updateHeight(node); int balanceFactor = getBalanceFactor(node); // 左旋操作 if (balanceFactor > 1 && key < node.left.key) { return rotateRight(node); } // 右旋操作 if (balanceFactor < -1 && key > node.right.key) { return rotateLeft(node); } // 左右旋操作 if (balanceFactor > 1 && key > node.left.key) { node.left = rotateLeft(node.left); return rotateRight(node); } // 右左旋操作 if (balanceFactor < -1 && key < node.right.key) { node.right = rotateRight(node.right); return rotateLeft(node); } return node; } // 中序遍历 void inorderTraversal(Node node) { if (node != null) { inorderTraversal(node.left); System.out.print(node.key + " "); inorderTraversal(node.right); } } } // 测试代码 public class Main { public static void main(String[] args) { AVLTree tree = new AVLTree(); tree.root = tree.insertNode(tree.root, 10); tree.root = tree.insertNode(tree.root, 20); tree.root = tree.insertNode(tree.root, 30); tree.root = tree.insertNode(tree.root, 40); tree.root = tree.insertNode(tree.root, 50); tree.root = tree.insertNode(tree.root, 25); System.out.println("AVL树的升序遍历结果:"); tree.inorderTraversal(tree.root); } } ``` 运行以上代码,输出结果为:10 20 25 30 40 50,即AVL树的升序遍历结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值