AVLTree/平衡二叉树

AVLTree/平衡二叉树

背景

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查
找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii
和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。

  • 1它的左右子树都是AVL树
  • 2 左右子树高度之差(简称平衡因子(右减左))的绝对值不超过1(-1/0/1)

树节点定义

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)
	{}
  • 与搜索树一样,带有父,左,右三个指针,便于插入查找
  • 带有一个_bf去存储平衡因子

树的插入与平衡的实现

1将节点插入进来
if (!_root)
{
	_root = new Node(kv);
	return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
	if (cur->_kv.first < kv.first)
	{
		parent = cur;
		cur = cur->_right;
	}
	else if (cur->_kv.first > kv.first)
	{
		parent = cur;
		cur = cur->_left;
	}
	else
		return false;
}
cur = new Node(kv);
if (parent->_kv.first < kv.first)
{
	parent->_right = cur;
	cur->_parent = parent;
}
else
{
	parent->_left = cur;
	cur->_parent = parent;
}

与搜索树一样

判断旋转方式

1不需要旋转(只改变每个节点的平衡因子即可)
2左旋

void RotateL(Node* parent)
{

	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	parent->_right = subRL;
	subR->_left = parent;
	Node* parentParent = parent->_parent;
	parent->_parent = subR;
	if (subRL)
	{
		subRL->_parent = parent;
	}
	if (_root==parent)
	{
		_root = subR;
		subR->_parent = nullptr;
	}
	else
	{
		if (parentParent->_left == parent)
		{
			parentParent->_left = subR;
		}
		else
		{
			parentParent->_right = subR;
		}
		subR->_parent = parentParent;
	}
	parent->_bf = subR->_bf = 0;
}

在这里插入图片描述
3右旋

 	void RotateR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	subL->_right = parent;
	parent->_left = subLR;
	Node* parentParent = parent->_parent;
	parent->_parent = subL;
	if (subLR)
	{
		subLR->_parent = parent;
	}
	if (_root == parent)
	{
		_root = subL;
		subL->_parent = nullptr;
	}
	else
	{
		if (parentParent->_left == parent)
		{
			parentParent->_left = subL;
		}
		else
		{
			parentParent->_right = subL;
		}
		subL->_parent = parentParent;
	}
	parent->_bf = subL->_bf = 0;
}

在这里插入图片描述
4左右旋

void RotateLR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	int bf = subLR->_bf;
	RotateL(subL);
	RotateR(parent);
	if (bf == 0)
	{
		subLR->_bf = subL->_bf = parent->_bf = 0;
	}
	else if (bf == -1)
	{
		subLR->_bf = subL->_bf = 0;
		parent->_bf = 1;
	}
	else if (bf == 1)
	{
		subLR->_bf = parent->_bf = 0;
		subL->_bf = -1;
	}
	else
	{
		assert(false);
	}
}

在这里插入图片描述
4右转旋

	void RotateRL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		int bf = subRL->_bf;
		RotateR(subR);
		RotateL(parent);
		if (bf == 0)
		{//subRL自增
			subRL->_bf = subR->_bf = parent->_bf = 0;
		}
		else if (bf == -1)
		{//subRL左树增加
			subRL->_bf = parent->_bf = 0;
			subR->_bf = 1;
		}
		else if (bf == 1)
		{//subRL右树增加
			subRL->_bf = subR->_bf = 0;
			parent->_bf = -1;
		}
		else
		{
			assert(false);
		}
	}

在这里插入图片描述

注:每次插入后一定要注意每个节点平衡因子的更新

完整代码

bool Insert(const pair<K, V>& kv)
{
	if (!_root)
	{
		_root = new Node(kv);
		return true;
	}
	Node* parent = nullptr;
	Node* cur = _root;
	while (cur)
	{
		if (cur->_kv.first < kv.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_kv.first > kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else
			return false;
	}
	cur = new Node(kv);
	if (parent->_kv.first < kv.first)
	{
		parent->_right = cur;
		cur->_parent = parent;
	}
	else
	{
		parent->_left = cur;
		cur->_parent = parent;
	}
	while (parent)
	{
		if (cur == parent->_left)
		{
			parent->_bf--;
		}
		else
		{
			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)
		{
			if (parent->_bf == 2 && cur->_bf == 1)
			{
				RotateL(parent);
			}
			else if (parent->_bf == -2 && cur->_bf == -1)
			{
				RotateR(parent);
			}
			else if (parent->_bf == -2 && cur->_bf == 1)
			{
				RotateLR(parent);
			}
			else
			{
				RotateRL(parent);
			}
			break;
			// 1、旋转让这颗子树平衡了
			// 2、旋转降低了这颗子树的高度,恢复到跟插入前一样的高度,所以对上一层没有影响,不用继续更新
		}
		else
		{
			assert(false);
		}
	}
	
}
  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C语言创建平衡二叉树的示例代码: ```c #include <stdio.h> #include <stdlib.h> // 定义平衡二叉树结点 typedef struct AVLNode { int data; // 数据域 int height; // 结点高度 struct AVLNode *left; // 左子树指针 struct AVLNode *right; // 右子树指针 } AVLNode, *AVLTree; // 获取结点高度 int getHeight(AVLTree T) { if (T == NULL) { return -1; } else { return T->height; } } // 获取两个数中的最大值 int max(int a, int b) { return a > b ? a : b; } // LL旋转 AVLTree LLRotation(AVLTree A) { AVLTree B = A->left; A->left = B->right; B->right = A; A->height = max(getHeight(A->left), getHeight(A->right)) + 1; B->height = max(getHeight(B->left), A->height) + 1; return B; } // RR旋转 AVLTree RRRotation(AVLTree A) { AVLTree B = A->right; A->right = B->left; B->left = A; A->height = max(getHeight(A->left), getHeight(A->right)) + 1; B->height = max(getHeight(B->right), A->height) + 1; return B; } // LR旋转 AVLTree LRRotation(AVLTree A) { A->left = RRRotation(A->left); return LLRotation(A); } // RL旋转 AVLTree RLRotation(AVLTree A) { A->right = LLRotation(A->right); return RRRotation(A); } // 插入结点 AVLTree insert(AVLTree T, int data) { if (T == NULL) { T = (AVLTree)malloc(sizeof(AVLNode)); T->data = data; T->height = 0; T->left = T->right = NULL; } else if (data < T->data) { T->left = insert(T->left, data); if (getHeight(T->left) - getHeight(T->right) == 2) { if (data < T->left->data) { T = LLRotation(T); } else { T = LRRotation(T); } } } else if (data > T->data) { T->right = insert(T->right, data); if (getHeight(T->right) - getHeight(T->left) == 2) { if (data > T->right->data) { T = RRRotation(T); } else { T = RLRotation(T); } } } T->height = max(getHeight(T->left), getHeight(T->right)) + 1; return T; } // 中序遍历 void inorderTraversal(AVLTree T) { if (T != NULL) { inorderTraversal(T->left); printf("%d ", T->data); inorderTraversal(T->right); } } int main() { AVLTree T = NULL; int arr[] = {3, 2, 1, 4, 5, 6, 7, 10, 9, 8}; int len = sizeof(arr) / sizeof(arr[0]); for (int i = 0; i < len; i++) { T = insert(T, arr[i]); } inorderTraversal(T); // 输出:1 2 3 4 5 6 7 8 9 10 return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值