数据结构---AVL树调整方法(详)

AVL树的调整整体分为两种:

  • 单旋转
  • 左单旋
  • 右单旋
  • 双旋转
  • 先左单旋,再右单旋
  • 先右单旋,再左单旋

在这里插入图片描述例如:上图想要将值为40的结点插入到AVL树中,只能将其插入到值为50的左孩子结点。
在这里插入图片描述这里的平衡因子为:右孩子树的高度减去左孩子树的高度。
由于AVL树的平衡因子为-1或1.因此,上图已经不满足AVL树的要求,所以要对其进行旋转调整。

单旋
一:右单旋

如何判断AVL树需要进行右单旋操作:新节点插入较高左子树的左侧,需要对其进行右单旋。

什么是较高左子树的左侧:

在这里插入图片描述
上图中,左子树的高度为2,右子树的高度为1,所以当新结点插入左子树的左孩子下方即称为较高左子树的左侧。
在这里插入图片描述上述两种情况统称为较高左子树的左侧。

如何调整:
在这里插入图片描述
上图中,结点80的平衡因子,已经不满足要求,需要将80的平衡因子降低(平衡因子是左右子数高度差的绝对值,为了方便描述,我这里的平衡因子是用右子数的高度减去左子树的高度,这里说的降低平衡因子,是是降低其绝对值)。解决办法是:提较高子树的根结点。上图中较高子树的根结点为60
在这里插入图片描述
在调成期间也需要考虑一些特殊的情况:
在这里插入图片描述
例如这种单支的情况,也满足右旋条件。

**注意:**在进行指向调整的同时,记得双亲结点的调整,最终记得调整每个结点的平衡因子。

在这里插入图片描述

//结合上图,Node是AVL树每个结点的结构体
void RotateR(Node* pParent) //右单旋,右侧的树高度降低
{
	Node* pSubL = pParent->_pLeft;
	Node* pSubLR = pSubL->_pRight;
	Node* pPParent = pParent->_pParent;

	pParent->_pLeft = pSubLR;
	if (pSubLR)
		pSubLR->_pParent = pParent;
	pSubL->_pRight = pParent;
	pSubL->_pParent = pPParent;
	pParent->_pParent = pSubL;
	if (pPParent == nullptr)
	{
		_pRoot = pSubL;
	}
	else 
	{
		if (pPParent->_pLeft == pParent)
			pPParent->_pLeft = pSubL;
		else if (pPParent->_pRight == pParent)
			pPParent->_pRight = pSubL;
	}

	pParent->_bf = pSubL->_bf = 0;
}
左单旋

左单旋:左子树高度降低,类似于右单旋的镜像。
什么情况下需要进行左单旋:插入结点插在较高右子树的右侧。
在这里插入图片描述
解决办法:将较高右子树的根结点往上提。
在这里插入图片描述
调整方法:
在这里插入图片描述
注意:在这里插入图片描述

void RotateL(Node* pParent)  //左单旋,左侧高度降低
{
	Node* pSubR = pParent->_pRight;
	Node* pSubRL = pSubR->_pLeft;
	Node* pPParent = pParent->_pParent;

	pParent->_pRight = pSubRL;
	if (pSubRL)
		pSubRL->_pParent = pParent;
	pSubR->_pLeft = pParent;
	pSubR->_pParent = pPParent;
	pParent->_pParent = pSubR;
	if (pPParent == nullptr)
	{
		_pRoot = pSubR;
	}
	else
	{
		if (pPParent->_pLeft == pParent)
			pPParent->_pLeft = pSubR;
		else
			pPParent->_pRight = pSubR;
	}

	pSubR->_bf = pParent->_bf = 0;
}
双旋
先右单旋,再左单旋

场景:插入结点在,较高右子树的左侧。
在这里插入图片描述上述两种情况都满足,插入结点在较高右子树的左侧。
在这里插入图片描述经过调整发现调整后的树,不满足AVL树的性质,但是满足AVL树,左单旋的条件,接着对其进行左单旋。
在这里插入图片描述

先左单旋,再右单旋

插入结点在较高左子树的右侧。
在这里插入图片描述调整过程:
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
平衡二叉树是一种特殊的二叉树,它的左右子树的高度差不超过1。AVL树是一种自平衡的二叉搜索树,它的高度始终保持在O(log n)。 下面是C语言实现平衡二叉树(AVL树)的代码: ``` #include <stdio.h> #include <stdlib.h> /* 定义平衡二叉树节点结构体 */ struct AVLNode { int data; // 存储的数据 int height; // 节点高度 struct AVLNode *leftChild; // 左子树 struct AVLNode *rightChild; // 右子树 }; /* 获取节点高度 */ int getHeight(struct AVLNode *node) { if (node == NULL) { return -1; } else { return node->height; } } /* 获取节点平衡因子 */ int getBalanceFactor(struct AVLNode *node) { if (node == NULL) { return 0; } else { return getHeight(node->leftChild) - getHeight(node->rightChild); } } /* 更新节点高度 */ void updateHeight(struct AVLNode *node) { node->height = 1 + (getHeight(node->leftChild) > getHeight(node->rightChild) ? getHeight(node->leftChild) : getHeight(node->rightChild)); } /* 右旋操作 */ struct AVLNode *rotateRight(struct AVLNode *node) { struct AVLNode *newRoot = node->leftChild; node->leftChild = newRoot->rightChild; newRoot->rightChild = node; updateHeight(node); updateHeight(newRoot); return newRoot; } /* 左旋操作 */ struct AVLNode *rotateLeft(struct AVLNode *node) { struct AVLNode *newRoot = node->rightChild; node->rightChild = newRoot->leftChild; newRoot->leftChild = node; updateHeight(node); updateHeight(newRoot); return newRoot; } /* 插入操作 */ struct AVLNode *insert(struct AVLNode *root, int data) { if (root == NULL) { root = (struct AVLNode *) malloc(sizeof(struct AVLNode)); root->data = data; root->height = 0; root->leftChild = NULL; root->rightChild = NULL; } else if (data < root->data) { root->leftChild = insert(root->leftChild, data); if (getHeight(root->leftChild) - getHeight(root->rightChild) == 2) { if (data < root->leftChild->data) { root = rotateRight(root); } else { root->leftChild = rotateLeft(root->leftChild); root = rotateRight(root); } } } else if (data > root->data) { root->rightChild = insert(root->rightChild, data); if (getHeight(root->rightChild) - getHeight(root->leftChild) == 2) { if (data > root->rightChild->data) { root = rotateLeft(root); } else { root->rightChild = rotateRight(root->rightChild); root = rotateLeft(root); } } } updateHeight(root); return root; } /* 中序遍历 */ void inOrderTraversal(struct AVLNode *root) { if (root != NULL) { inOrderTraversal(root->leftChild); printf("%d ", root->data); inOrderTraversal(root->rightChild); } } int main() { struct AVLNode *root = NULL; int data[] = {5, 2, 8, 1, 3, 6, 9}; int len = sizeof(data) / sizeof(data[0]); int i; for (i = 0; i < len; i++) { root = insert(root, data[i]); } inOrderTraversal(root); return 0; } ``` 以上代码实现了平衡二叉树的插入和中序遍历操作。在插入操作中,根据插入节点的值和当前节点的值的大小关系,不断递归向左或向右子树进行插入操作,并在递归返回时更新节点高度和进行平衡操作。在平衡操作中,根据节点的平衡因子进行旋转操作,使树重新平衡。在中序遍历操作中,按照左子树、根节点、右子树的顺序遍历树中的节点,输出节点的值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值