二叉搜索树 AVLTree

1.二叉搜索树

顾名思义 一个用于搜索的二叉树
1.1二叉树的性质
1.若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
2.若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
3.它的左右子树也分别为二叉搜索树

它的性质决定了它的中序遍历就是这组数据的有序排列
1.2二叉树的建立
和二叉树一样 找到一颗树只需要记录根节点就行
在这里插入图片描述

节点
在这里插入图片描述
插入节点
从根节点开始遍历 比节点值大就往右走 比节点值小就往左走 直到找到空位置就插入数据
在这里插入图片描述
删除节点
如果是叶子节点就直接删除 如果要删除节点存在子树就要找 左子树做大节点或者右子树最小节点替换这个节点然后删除

查找节点 直接根据特性遍历就行了

二叉搜索树实现

2.AVLTree

我们可以发现 二叉搜索树 正常情况下 查找数据的复杂度为log n 还是很快的
但依然存在一些特殊情况 当后面插入的数据都比根节点的值都大或都更小 那么这个树就退化成了歪脖子树 就像一个链表一样
而AVLTree就是为了解决这个问题而产生的 AVLTree又叫二叉平衡搜索树
这个树相比于二叉搜索树最大的差别就是平衡
当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整)就实现了平衡
所以在节点引入了一个平衡因子 右数高度减左数高度 平衡因子绝对值小于二就表示其为平衡的

template<class T>
struct AVLTreeNode
{
 AVLTreeNode(const T& data)
     : _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr)
 , _data(data), _bf(0)
 {}
 AVLTreeNode<T>* _pLeft;   // 该节点的左孩子
 AVLTreeNode<T>* _pRight;  // 该节点的右孩子
 AVLTreeNode<T>* _pParent; // 该节点的双亲
 T _data;
 int _bf;                  // 该节点的平衡因子
};

那如何保证平衡呢
当插入数据后就可能会使某个数高度发生变化就会影响平衡因子 当平衡因子绝对值大于1时就将这个树进行旋转
2.1旋转
AVL旋转有四种情况

  1. 新节点插入较高左子树的左侧—左左:右单旋
void rotar(node* parent)//右单旋
	{
		node* nodel = parent->_left;
		node* nodelr = nodel->_right;
		node* ppnode = parent->_parent;

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

		nodel->_right = parent;
		parent->_parent = nodel;

		if (ppnode == nullptr)
		{
			_root = nodel;
			nodel->_parent = nullptr;
		}
		else
		{
			if (parent == ppnode->_left)
			{
				ppnode->_left = nodel;
			}
			else if (parent == ppnode->_right)
			{
				ppnode->_right = nodel;
			}
			nodel->_parent = ppnode;
		}
		parent->bf = nodel->bf = 0;
	}
  1. 新节点插入较高右子树的右侧—右右:左单旋
    在这里插入图片描述
void rotal(node* parent)//左单旋
	{
		node* noder = parent->_right;
		node* noderl = noder->_left;
		node* ppnode = parent->_parent;

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

		noder->_left = parent;
		parent->_parent = noder;

		if (ppnode == nullptr)
		{
			_root = noder;
			_root->_parent = nullptr;
		}
		else
		{
			if (parent == ppnode->_left)
			{
				ppnode->_left = noder;

			}
			else if (parent == ppnode->_right)
			{
				ppnode->_right = noder;
			}
			noder->_parent = ppnode;
		}
		parent->bf = noder->bf = 0;
	}
  1. 新节点插入较高左子树的右侧—左右:先左单旋再右单旋
    在这里插入图片描述
void rotalr(node* parent)//双旋 左右
	{
		node* nodel = parent->_left;
		node* nodelr = nodel->_right;
		int bf = parent->_left->_right->bf;
		rotal(parent->_left);
		rotar(parent);
		if (bf == -1)
		{
			nodel->bf = 0;
			parent->bf = 1;
			nodelr = 0;
		}
		else if (bf == 1)
		{
			nodel->bf = -1;
			parent->bf = 0;
			nodelr = 0;
		}
		else if (bf == 0)
		{
			nodel->bf = 0;
			parent->bf = 0;
			nodelr = 0;
		}
		else
		{
			assert(false);
		}
	}
  1. 新节点插入较高右子树的左侧—右左:先右单旋再左单旋
    在这里插入图片描述
void rotarl(node* parent)//双旋 右左
	{
		node* noder = parent->_right;
		node* noderl = noder->_left;
		int bf = parent->_right->_left->bf;
		rotar(parent->_right);
		rotal(parent);
		if (bf == -1)
		{
			noder->bf = 1;
			parent->bf = 0;
			noderl->bf = 0;
		}
		else if (bf == 1)
		{
			noder->bf = 0;
			parent->bf = -1;
			noderl->bf = 0;
		}
		else if (bf == 0)
		{
			noder->bf = 0;
			parent->bf = 0;
			noderl->bf = 0;
		}
		else
		{
			assert(false);
		}
	}

注意更新平衡因子
AVLTree模拟

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值