xiejunyan的平衡二叉树操作的演示

#include <malloc.h>
#include "stdio.h"
#include <string.h>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1
typedef int Status;
typedef int KeyType;

typedef struct RcdType {
    KeyType key;
}RcdType;
typedef struct BBSTNode {
    RcdType data;
    int height = 0;
    struct BBSTNode* lchild, * rchild;
}BBSTNode, * BBSTree;

BBSTree NULLTree = (BBSTree)malloc(sizeof(BBSTNode));

int max(int i, int j) {
    return (i > j) ? i : j;
}

Status InitAVL(BBSTree& T) {
    T = NULLTree;
    return OK;
}

void DestroyBBST(BBSTree& T) {

    //采用递归的方法后序遍历平衡二叉树,访问结点时销毁该结点。
    if (NULLTree != T) {
        DestroyBBST(T->lchild);
        DestroyBBST(T->rchild);

        free(T);
    }
}

void LL_rotate(BBSTree& T) {
    BBSTree lc;
    lc = T->lchild;
    int lclcH = lc->lchild->height;
    int lcrcH = lc->rchild->height;
    int rcH = T->rchild->height;//先把高度储存起来

    T->lchild = lc->rchild;
    lc->rchild = T;
    T = lc;//完成变换

    T->rchild->height = max(lcrcH, rcH) + 1;
    T->height = max(lclcH, T->rchild->height) + 1;
    NULLTree->height = 0;        //完成高度修改
}
void RR_rotate(BBSTree& T) {
    BBSTree rc;
    rc = T->rchild;
    int lcH = T->lchild->height;
    int rclcH = rc->lchild->height;
    int rcrcH = rc->rchild->height;//先把高度储存起来

    T->rchild = rc->lchild;
    rc->lchild = T;
    T = rc;//完成变换

    T->lchild->height = max(lcH, rclcH) + 1;
    T->height = max(rcrcH, T->lchild->height) + 1;
    NULLTree->height = 0;      //完成高度修改
}
void LR_rotate(BBSTree& T) {
    RR_rotate(T->lchild);
    LL_rotate(T);
}
void RL_rotate(BBSTree& T) {
    LL_rotate(T->rchild);
    RR_rotate(T);
}
void InsertAVL(BBSTree& T, RcdType e, Status& ok_error) {
    //结束:到达叶子,或已有该值结点存在则不插入
    //分解:插入的值小于当前结点左递归插入,大于则右递归插入
    //组合:在逐层回溯的时候,调整平衡

    if (NULLTree == T) {
        T = (BBSTree)malloc(sizeof(BBSTNode));
        T->data = e;
        T->height = 1;
        T->lchild = T->rchild = NULLTree;
        ok_error = OK;
        NULLTree->height = 0;
    }
    else if (T->data.key == e.key) ok_error = ERROR;
    else if (e.key < T->data.key) {
        InsertAVL(T->lchild, e, ok_error);
        if (T->lchild->height - T->rchild->height == 2) {
            if (e.key < T->lchild->data.key) LL_rotate(T);//说明之前是往左插入
            else LR_rotate(T);
        }
        else T->height = max(T->lchild->height, T->rchild->height) + 1;
    }
    else if (e.key > T->data.key) {
        InsertAVL(T->rchild, e, ok_error);
        if (T->rchild->height - T->lchild->height == 2) {
            if (e.key > T->rchild->data.key) RR_rotate(T);//说明之前是往右插入
            else RL_rotate(T);
        }
        else T->height = max(T->lchild->height, T->rchild->height) + 1;
    }
}

void L_rotate(BBSTree& T) {
    if (T->lchild->rchild->height > T->lchild->lchild->height) {
        LR_rotate(T);
    }
    else LL_rotate(T);
}
void R_rotate(BBSTree& T) {
    if (T->rchild->lchild->height > T->rchild->rchild->height) {
        RL_rotate(T);
    }
    else RR_rotate(T);
}
RcdType find_maxleft(BBSTree lc) {
    //用于在当前要删除结点左右子树都不为空且左子树高或一样高,的情况下找到当前要删除结点直接前驱
    while (NULLTree != lc->rchild) {
        lc = lc->rchild;
    }
    return lc->data;
}
RcdType find_minright(BBSTree rc) {
    //用于在当前要删除结点左右子树都不为空且右子树高,的情况下找到当前要删除结点直接后驱
    while (NULLTree != rc->lchild) {
        rc = rc->lchild;
    }
    return rc->data;
}


void DeleteAVL(BBSTree& T, RcdType e, Status& ok_error, Status& can_end) {
    //结束:找到要删的结点,或到NULLTree结点
    //分解:要删的结点小于当前结点,左递归删除,大于则右递归删除
    //组合:从被删结点的“父节点”开始,逐层回溯,检查是否不平衡;若不平衡则调整,到根结点,或“调整后树的高度没有变化”就结束。
    if (NULLTree == T) {
        ok_error = ERROR;
        can_end = TRUE;
    }
    else if (T->data.key == e.key) {
        if (NULLTree == T->rchild) {//叶子结点,和仅右子树为空的情况
            BBSTree temp = T;
            T = T->lchild;
            free(temp);
            ok_error = OK;
        }
        else if (NULLTree == T->lchild) {//仅左子树为空的情况
            BBSTree temp = T;
            T = T->rchild;
            free(temp);
            ok_error = OK;
        }
        else {//左右结点都不为空的情况
            if (T->lchild->height >= T->rchild->height) {
                RcdType temp_e;
                temp_e = find_maxleft(T->lchild);
                T->data = temp_e;//仅赋值,属于“假删除”
                Status can_end_temp = FALSE;
                DeleteAVL(T->lchild, temp_e, ok_error, can_end_temp);
                T->height = max(T->lchild->height, T->rchild->height) + 1; //及时调整高度,否则回溯到父节点
            }
            else {
                RcdType temp_e;
                temp_e = find_minright(T->rchild);
                T->data = temp_e;//仅赋值,属于“假删除”
                Status can_end_temp = FALSE;
                DeleteAVL(T->rchild, temp_e, ok_error, can_end_temp);
                T->height = max(T->lchild->height, T->rchild->height) + 1;//及时调整高度,否则回溯到父节点
            }
        }
    }
    else if (e.key < T->data.key) {
        DeleteAVL(T->lchild, e, ok_error, can_end);
        if (!can_end) {
            if (T->rchild->height - T->lchild->height == 2) {
                R_rotate(T);
            }
            else {  //如果调整之后当前结点高度没有变化,则不必要向上回溯调整
                int old_height = T->height;
                T->height = max(T->lchild->height, T->rchild->height) + 1;
                can_end = (old_height == T->height) ? TRUE : FALSE;
            }
        }
    }
    else {
        DeleteAVL(T->rchild, e, ok_error, can_end);
        if (!can_end) {
            if (T->lchild->height - T->rchild->height == 2) {
                L_rotate(T);
            }
            else {  //如果调整之后当前结点高度没有变化,则不必要向上回溯调整
                int old_height = T->height;
                T->height = max(T->lchild->height, T->rchild->height) + 1;
                can_end = (old_height == T->height) ? TRUE : FALSE;
            }
        }
    }
}

BBSTree SearchBBST(BBSTree T, KeyType key) {
    //在平衡二叉树中查找某个值
    if (NULLTree == T) return NULLTree;
    else if (T->data.key == key) return T;
    else if (key < T->data.key) return SearchBBST(T->lchild, key);
    else return SearchBBST(T->rchild, key);
}

void print(BBSTree T, int space_number)//凹入表打印树结构 
{
    if (T != NULLTree)
    {
        print(T-> rchild, space_number + 1);
        for (int i = 0; i < space_number; i++) printf("   ");
        printf("%d\n", T->data.key);
        print(T-> lchild, space_number + 1);
    }
}

void CopyTree(BBSTree t1, BBSTree &t) {
    //把t1的结点全都插入到t中
    if (NULLTree != t1) {
        Status temp;
        InsertAVL(t, t1->data, temp);

        CopyTree(t1->lchild, t);
        CopyTree(t1->rchild, t);
    }
}

BBSTree MixTree(BBSTree t1, BBSTree t2) {
    BBSTree t;
    InitAVL(t);
    CopyTree(t1, t); CopyTree(t2, t);
    return t;
}

void SplitTree(BBSTree t, BBSTree& t1, BBSTree& t2, int key) {
    if (NULLTree != t) {
        Status temp = ERROR;
        if (t->data.key <= key) InsertAVL(t1, t->data, temp);
        else InsertAVL(t2, t->data, temp);

        SplitTree(t->lchild, t1, t2, key);
        SplitTree(t->rchild, t1, t2, key);
    }
}


int main()
{
    printf("                                            平衡二叉树操作的演示\n");
    printf("一开始你拥有10棵空树,编号分别为0 1 2 3 4 5 6 7 8 9 名字是t0 t1 t2 t3 t4 t5 t6 t7 t8 t9\n");
    printf("本程序有5种操作:1:查找 需要 查找的树的编号/key\n");
    printf("                 2:插入 需要 插入的树的编号/一系列要插入的key\n");
    printf("                 3:删除 需要 删除的树的编号/一系列要删除的key\n");
    printf("                 4:合并 需要 合并的两棵树的编号/存放合并后的树的编号\n");
    printf("                 5:分裂 需要 要分裂的树的编号/存放分裂后的两棵树的编号/分裂参照值key\n");
    printf("当要插入或删除一系列key时,输入格式为:key(空格)key(空格)key(ctrl+z) 例如:4 5 6 7 8 9(ctrl+z)\n");
    printf("当树已存在key,插入失败;当树不存在key, 删除失败\n\n");
    printf("ps:运行程序时,请按照要求和提示操作;输入树的编号请在合理范围内\n\n\n\n");

    BBSTree t0 = NULL, t1 = NULL, t2 = NULL, t3 = NULL, t4 = NULL, t5 = NULL, t6 = NULL, t7 = NULL, t8 = NULL, t9 = NULL;
    BBSTree forest[10] = { t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 };
    const char* forest_name[10] = { "t0","t1","t2","t3","t4","t5","t6","t7","t8","t9" };
    int do_index;//操作编号
    int tree1_number;//要操作的1树序号
    int tree2_number;//要操作的2树序号
    int tree3_number;//要操作的3树序号
    int search_key;//要查找的数据的key值
    int split_key;//分裂操作中的关键字
    int go_flag = 1;//是否继续程序
    char print_y_n;//是否打印
    RcdType e; e.key = 0;//负责存储临时的插入值或删除值
    Status ok_error = OK;//存储是否插入或删除成功的状态值
    Status can_end = FALSE;//存储是否可以中途结束删除的状态值
    for (int i = 0; i < 10; i++) InitAVL(forest[i]);

    while (go_flag) {
        printf("请输入要进行的操作的序号:");
        scanf_s("%d", &do_index);

        switch (do_index) {
        case 1: {
            printf("\n请输入要查找的树的编号:");
            scanf_s("%d", &tree1_number);
            printf("请输入要查找的key值:");
            scanf_s("%d", &search_key);
            if (NULLTree == SearchBBST(forest[tree1_number], search_key)) {
                printf("\n在%s中找不到%d", forest_name[tree1_number], search_key);
            }
            else printf("\n在%s中找到了%d", forest_name[tree1_number], search_key);
            
            printf("\n要显示树%s吗(y or n):", forest_name[tree1_number]);
            getchar();
            scanf_s("%c", &print_y_n);
            if (print_y_n == 'y') print(forest[tree1_number], 0);
            break;
        }
        case 2: {
            printf("\n请输入要插入结点的树的编号:");
            scanf_s("%d", &tree1_number);
            printf("请输入要插入的key值(多个值之间以空格隔开,以ctrl+z结尾):");
            while (scanf_s("%d", &e.key)) {
                InsertAVL(forest[tree1_number], e, ok_error);
                if (ok_error == OK) printf("在%s中成功插入%d\n", forest_name[tree1_number], e.key);
                else printf("在%s中插入%d失败\n", forest_name[tree1_number], e.key);
            }

            printf("要显示树%s吗(y or n):", forest_name[tree1_number]);
            getchar();
            scanf_s("%c", &print_y_n);
            if (print_y_n == 'y') print(forest[tree1_number], 0);
            break;
        }
        case 3: {
            printf("\n请输入要删除结点的树的编号:");
            scanf_s("%d", &tree1_number);
            printf("请输入要删除的key值(多个值之间以空格隔开,以ctrl+z结尾):");
            while (scanf_s("%d", &e.key)) {
                DeleteAVL(forest[tree1_number], e, ok_error, can_end);
                if (ok_error == OK) printf("在%s中成功删除%d\n", forest_name[tree1_number], e.key);
                else printf("在%s中删除%d失败\n", forest_name[tree1_number], e.key);
                can_end = FALSE;
            }

            printf("要显示树%s吗(y or n):", forest_name[tree1_number]);
            getchar();
            scanf_s("%c", &print_y_n);
            if (print_y_n == 'y') print(forest[tree1_number], 0);
            break;
        }
        case 4: {
            printf("\n请输入想合并的第一棵树的编号:");
            scanf_s("%d", &tree1_number);
            print(forest[tree1_number], 0);
            printf("\n请输入想合并的第二棵树的编号:");
            scanf_s("%d", &tree2_number);
            print(forest[tree2_number], 0);
            printf("\n你想把合并后的树存放到哪棵树中:");
            scanf_s("%d", &tree3_number);

            BBSTree t_temp;
            t_temp = MixTree(forest[tree1_number], forest[tree2_number]);
            DestroyBBST(forest[tree3_number]);
            forest[tree3_number] = t_temp;

            printf("要显示树%s吗(y or n):", forest_name[tree3_number]);
            getchar();
            scanf_s("%c", &print_y_n);
            if (print_y_n == 'y') print(forest[tree3_number], 0);
            break;
        }
        case 5: {
            printf("\n请输入想分裂的树的编号:");
            scanf_s("%d", &tree1_number);
            print(forest[tree1_number], 0);
            printf("\n请输入分裂操作中的关键字:");
            scanf_s("%d", &split_key);
            printf("请输入存放小于或等于%d的树的编号:", split_key);
            scanf_s("%d", &tree2_number);
            printf("请输入存放大于%d的树的编号:", split_key);
            scanf_s("%d", &tree3_number);

            BBSTree t_temp1, t_temp2;
            InitAVL(t_temp1); InitAVL(t_temp2);
            SplitTree(forest[tree1_number], t_temp1, t_temp2, split_key);
            DestroyBBST(forest[tree2_number]); DestroyBBST(forest[tree3_number]);
            forest[tree2_number] = t_temp1; 
            forest[tree3_number] = t_temp2;

            printf("要显示树%s吗(y or n):", forest_name[tree2_number]);
            getchar();
            scanf_s("%c", &print_y_n);
            if (print_y_n == 'y') print(forest[tree2_number], 0);
            printf("要显示树%s吗(y or n):", forest_name[tree3_number]);
            getchar();
            scanf_s("%c", &print_y_n);
            if (print_y_n == 'y') print(forest[tree3_number], 0);
            break;
        }
        }
        printf("想继续这个程序吗(1 or 0):");
        scanf_s("%d", &go_flag);
    }
    for (int i = 0; i < 10; i++) DestroyBBST(forest[i]);
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值