二叉排序树查找c++_avl树(带有平衡条件的二叉查找树)—C

eb01bca897b0407d0b11fe0d89388b87.png

再讲avl树之前我们要先了解什么是二叉查找树。

二叉查找树:

f00480ef70c140eed5eabe06c37571d5.png

如图为二叉查找树:

1.左子树的所有节点小于根节点

2.右子树的所有节点大于根节点

3.左右子树均为二叉查找树

关于二叉查找树的创建可以参考下面这个文章:

夜猫子:二叉查找树的创建和基本操作—c语言​zhuanlan.zhihu.com
9d63838509834e2864362a0d080a765f.png

引入avl树的原因:二叉查找树的特点就是能够快速查找数据,如上图,若查找2,则从左子树开始查找,若查找8,则从右子树查找。所以说,二叉查找树的时间复杂度一般情况下为O(logN)。但是如果发生以下情况:

9ba3b44229c481c0dac57e45480f569a.png

如果想要查1的话,原来的二叉树查找就变为了链表表即线性的查找,时间复杂度就变为O(oN),所以为了在特殊情况下仍保持O(logN)的时间复杂度,我们需要将树变换,我们引入了avl树。

avl树:

ec8db7f4e79ef9223508854914a6af5e.png

如图,根节点5的深度为-1,则左子树的深度为2,右子树的深度为1

avl树的特点:

1.每个节点的左右子树深度都相差1或0.

2.具有二查找树的全部特点

如图,该数不是avl树,左右子树:

2c8f0618d9cf7c9eab4d3e74870cc9d0.png

结点为5的树不平衡,左右深度差为2

62412f080bf53b03e1220372c9b4d079.png

结点为8的树不平衡,左右深度相差为2,不是avl树。

avl树的创建:

  • 单旋:

1.左儿子的左子树插入(左左)——右旋

0ababfe44703198570813a4b830612cf.png

2.右儿子的右子树插入(右有)——左旋

424d7cc2a1a5b86e0a7204473cc7f419.png
  • 双旋:

1.右儿子的左子树插入(右左)——先右旋再左旋

1a6bc969729fdb7233fc3f03bffaf6e3.png

如图,6为失衡点,在右儿子(9)的右子树(8)插入节点5,所以两次旋转,先右旋在左旋

2.左儿子的右子树插入(左右)——先左旋再右旋

32bb4ae2ecd3ea379930c1e416a5957d.png

如图,7为失衡点,在左儿子(3)的右子树(4)插入节点5,所以两次旋转,先左旋在右旋

总结:

判断是单旋还是双旋,要先确定失衡点,确定失衡点后四种情况来确定单旋还是双旋

代码实现(递归):

#include<stdio.h>
#include<stdlib.h>
#define MaxSize 10
typedef struct TreeNode* Position;
typedef struct TreeNode* AvlTree;
typedef struct TreeNode* SearchTree;
Position Find(int x, AvlTree T);
typedef struct TreeNode {
    AvlTree left;
    AvlTree right;
    int Height;
    int data;
}*Bintree;
Bintree InitTree(int x, AvlTree T);//创建二叉查找树
Bintree InitAvlTree(int x, SearchTree T);//创建avl树
//max和height函数用来计算树高
int Max(int T1, int T2) {
    return T1 >= T2 ? T1 : T2;
}
int Height(AvlTree T) {
    if (T == NULL)
    return -1;
    else 
    return T->Height;
}
//右旋
Position SingleRotateWithRight(AvlTree K2) {
    Position K1;
    K1=K2->left;
    K2->left = K1->right;
    K1->right = K2;
    K2->Height = Max(Height(K2->left), Height(K2->right)) + 1;
    K1->Height = Max(Height(K1->left), K2->Height);//更新树的高度
    return K1;
}
//左旋
Position SingleRotateWithLeft(AvlTree K2) {
    Position K1;
    K1 = K2->right;
    K2->right = K1->left;
    K1->left= K2;
    K2->Height = Max(Height(K2->left), Height(K2->right)) + 1;
    K1->Height = Max(Height(K1->right), K2->Height);//更新树的高度
    return K1;
}
//双旋:先左旋再右旋
Position  DoubleRotateWithLeftAndRight(AvlTree K3) {
    K3->left = SingleRotateWithLeft(K3->left);
    return SingleRotateWithRight(K3);
}
//双旋:先右旋再左旋
Position  DoubleRotateWithRightAndLeft(AvlTree K3) {
    K3->right = SingleRotateWithRight(K3->right);
    return SingleRotateWithLeft(K3);
}
//构造二叉查找树树
Bintree InitTree(int x, SearchTree T) {
    int i = 0;
    if (T == NULL) {
        T = (Bintree)malloc(sizeof(struct TreeNode));
        if (T == NULL)
            return 0;
        else {
            T->data = x;
            T->right = NULL;//先右节点,在左节点
            T->left = NULL;
        }
    }
    else if (x < T->data) {
        T->left = InitTree(x, T->left);
    }
    else if (x > T->data) {
        T->right = InitTree(x, T->right);
    }
    else
        printf("%d has insertedn", x);
    return T;
}
//构造avl树
Bintree InitAvlTree(int x, AvlTree T) {
    int i = 0;
    if (T == NULL) {
        T = (Bintree)malloc(sizeof(struct TreeNode));
        if (T == NULL)
            return 0;
        else {
            T->data = x;
            T->right = NULL;
            T->left = NULL;
            T->Height = 0;
        }
    }
    else if (x < T->data) {
        T->left = InitAvlTree(x, T->left);//插入节点过程
        if (Height(T->left) - Height(T->right) == 2) {//是否旋转的条件判断
            if (x < T->left->data)//左左情况单旋
                T = SingleRotateWithRight(T);//进行右旋
            else//左右情况双旋:先左旋再右旋
                T = DoubleRotateWithLeftAndRight(T);//Left表示左右情况
        }
    }
    else if (x > T->data) {//右右和右左情况
        T->right = InitAvlTree(x, T->right);
        if (Height(T->right) - Height(T->left) == 2) {
            if (x > T->right->data)
                T = SingleRotateWithLeft(T);
            else
                T = DoubleRotateWithRightAndLeft(T);
        }
    }
    else
        printf("%d has inserted,we'll do nothingn", x);
    T->Height = Max(Height(T->left), Height(T->right))+1;//计算高度
    return T;
}
//先序遍历
void Preorder(Bintree p)
{
    if (p != NULL)
    {
        printf("%dt", p->data);
        Preorder(p->left);
        Preorder(p->right);
    }
}
//中序遍历
void Inorder(Bintree p)
{
    if (p != NULL)
    {
        Inorder(p->left);
        printf("%dt", p->data);
        Inorder(p->right);
    }
}
//后序遍历
void Postorder(Bintree p)
{
    if (p != NULL)
    {
        Postorder(p->left);
        Postorder(p->right);
        printf("%dt", p->data);
    }
}
int main() {//为了方便观察主函数写的较为冗余
    Bintree p1 = NULL,p2=NULL;
    int a[MaxSize],num;
    printf("scanf element number:");
    scanf_s("%d", &num);
    printf("scanf element:");

    for (int i = 0; i < num; i++) {
        scanf_s("%d", &a[i]);
        p1= InitTree(a[i], p1);
        p2 = InitAvlTree(a[i], p2);
    }
    printf("Preorder is:");//先序遍历
    Preorder(p1);
    printf("n");
    printf("Inorder is:");//中序遍历
    Inorder(p1);
    printf("n");
    printf("Postorder is:");//后序遍历
    Postorder(p1);
    printf("n");
    printf("avltree:n");//改进后avl树
    printf("Preorder is:");//先序遍历
    Preorder(p2);
    printf("n");
    printf("Inorder is:");//中序遍历
    Inorder(p2);
    printf("n");
    printf("Postorder is:");//后序遍历
    Postorder(p2);
    printf("n");
    return 0;
}

代码测试:

单旋:

882b7a5d71042b091d15090a66d5749c.png

4e53277c855bd0a781dd94e1f032a880.png

a4e881ec32880f0b28f0b83ce72640ec.png

测试结果与预算结果相同,单旋测试成功

双旋:

b9f1ef837b4b5d4adbe7fba92280a8fc.png

f01418d4915e1177bcf0600cd2e692fe.png

d8653853c11e689d33e5d69ca3d2487e.png

与预期结果相同,测试成功

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值