目录
二叉搜索树的缺点
我们现在有一个这样的二叉搜索树:
像这样的二叉搜索树,我们想找到50这个节点,我们用遍历5次,时间复杂度O(n),这样是不是就违背了我们用二叉搜索树的初衷呢,与其如此我还不如实现一个其他算法呢!!!这就是为什么我们要学习平衡二叉树
将失调的二叉搜索树该能AVL树有以下这几种情况
必要调整之后满足两个条件:1.是二叉搜索树 2.每个节点的平衡因子的绝对值应该小于等于1
第一种:左旋
修改方式:1.当前右子树会作为新树的根节点2.当前节点会作为新树根节点的左子树
3.如果原来右子树上有左节点,那左节点应该作为旧根的右节点
第二种:右旋
调整方式:1.当前左节点会成为新的根节点 2.旧根节点会作为新根节点的右孩子
3.如果原来左节点上有右节点,那么这个节点作为旧根节点的左孩子
什么时候会遇见失衡呢?失衡了应该怎么办呢?
LL型失衡(左旋)
但我们对一棵二叉搜索树进行插入元素的操作的时候见下图,如果我们在数值为20的节点上插入一个左节点,就成下面的那张图的样子,是不是就失衡了呢?我们用 左子树的深度-右子树的深度 看他的绝对值大小 下面那张图我们就对树进行右旋操作 应为失衡的原因是: root的左孩子Left的左子树Left ,我们也称这种失衡为LL型失衡
LR型失衡(左旋+右旋)
我们不向左节点去插入元素了,我们向20的右节点插入元素,就成下面这个图示的样子,我们向20的节点插入一个25的节点,我们发现这个二叉搜索树失衡了!!!root的左孩子Left的右子树Right导致失衡 ,那我们先左旋再右旋 我们称为LR型
我们先对20和25节点进行左旋
左旋完之后我们对整体进行右旋
RR型失衡(右旋)
当我们在40的右节点上插入一个节点50的时候,因为在根节点右子树的上的右节点上插入元素导致失衡,这叫RR型失衡,直接右旋就行了
RL型失衡(右旋+左旋)
当我们在上面的右节点40的左节点插入45,使得树不平衡,这是RL型失衡
遇见这种失衡,我们先右旋在左旋
我们先对35和40进行右旋,再对30,35,40进行左旋
我们看看代码
#include<iostream>
#include<string>
using namespace std;
struct TreeNode {
int val;
int height;
struct TreeNode* left;
struct TreeNode* right;
};
TreeNode* newNode(int data)
{
TreeNode* node = new TreeNode();
node->val = data;
node->height = 1;
node->left = NULL;
node->right = NULL;
return node;
}
//获取树的高度
int GetHeight(TreeNode* node)
{
if (node == NULL)
{
return 0;
}
return node->height;
}
int max(int a, int b)
{
return a > b ? a : b;
}
//定义左旋函数
TreeNode* leftRoate(TreeNode* root)
{
//当前节点的右子树会作为新树的根节点
//当前节点会作为新树的根节点的左子树
//如果新的树根原来有左子树,那么原来的左子树会作为旧根节点的右子树
//*************************************************
//当前节点的右子树会作为新树的根节点
TreeNode* newroot = root->right;
//如果新的树根原来有左子树
//T2保存新树根原来的左子树
TreeNode* T2 = newroot->left;
//当前节点会作为新树的根节点的左子树
newroot->left = root;
//那么原来的左子树会作为旧根节点的右子树
root->right = T2;
//更新树高
root->height = 1 + max(GetHeight(root->left), GetHeight(root->left));
newroot->height = 1 + max(GetHeight(newroot->left), GetHeight(newroot->left));
return newroot;
}
//定义右旋函数
//当前节点的左子树会作为新树的根节点
//当前节点会作为新树的根节点的右子树
//如果新的树根原来有右子树,那么原来的左子树会作为旧根节点的右子树
TreeNode* rightRotate(TreeNode* root)
{//当前节点的左子树会作为新树的根节点
TreeNode* newroot = root->left;
//如果新的树根原来有右子树,那么原来的左子树会作为旧根节点的右子树
TreeNode* T2 = newroot->right;
newroot->right = root;
root->left = T2;
//更新树高
root->height = 1 + max(GetHeight(root->left), GetHeight(root->left));
newroot->height = 1 + max(GetHeight(newroot->left), GetHeight(newroot->left));
return newroot;
}
//定义函数,获取平衡因子
int getBalance(TreeNode* node)
{
return GetHeight(node->left) - GetHeight(node->right);
}
//定义插入节点的函数
TreeNode* insertNode(TreeNode* node, int key)
{
if (node == NULL)
return newNode(key);
if (key < node->val)
node->left = insertNode(node->left, key);
else if (key > node->val)
node->right = insertNode(node->right, key);
else
return node;
//更新树高
node->height = 1 + max(GetHeight(node->left), GetHeight(node->right));
//获取当前节点的平衡因子
int balance = getBalance(node);
//我们是否需要调整这个树,是看平衡因子是不是绝对值大于1
//LL型失衡
if (balance > 1 && getBalance(node->left) > 0)
{
return rightRotate(node);
}
//LR型失衡
if (balance > 1 && getBalance(node->left) < 0)
{
node->left = leftRoate(node->left);
return rightRotate(node);
}
//RR型失衡
if (balance < -1 && getBalance(node->right) < 0)
{
return leftRoate(node);
}
//RL型失衡
if (balance < -1 && getBalance(node->right)>0)
{
node->right = rightRotate(node->right);
return leftRoate(node);
}
return node;
}
TreeNode* find(TreeNode* root, int key, int* counter)
{
TreeNode* cur = root;
while (cur != NULL)
{
if (key < cur->val)
{
cur = cur->left;
(*counter)++;
}
else if (key > cur->val)
{
cur = cur->right;
(*counter)++;
}
else {
(*counter)++;
return cur;
}
}
return NULL;
}
//先序遍历
void preOrder(TreeNode* root)
{
if (root == NULL)
{
cout << "NULL" << " ";
return;
}
cout << root->val << " ";
preOrder(root->left);
preOrder(root->right);
}
void Inorder(TreeNode* root)
{
if (root == NULL)
{
cout << "NULL" << " ";
return;
}
Inorder(root->left);
cout << root->val << " ";
Inorder(root->right);
}
void test()
{
TreeNode* root = NULL;
root = insertNode(root, 10);
root = insertNode(root, 20);
root = insertNode(root, 30);
root = insertNode(root, 40);
root = insertNode(root, 50);
root = insertNode(root, 60);
root = insertNode(root, 70);
int counter = 0;
TreeNode* result = find(root, 70, &counter);
cout << counter << endl;
cout << "前序打印结果" << endl;
preOrder(root);
cout << endl;
cout << "中序打印结果" << endl;
Inorder(root);
}
int main()
{
test();
return 0;
}