二叉搜索树的创建(插入)、查找、删除、遍历(中序非递归)

久未见 提交于 2020-02-29 21:52:10

最近在学数据结构,前段时间学了二叉搜索树和平衡二叉树,但当时眼高手低就看了网课啥也没敲。。现在优点愧疚,就补上了。
二叉搜索树:
使用二分查找的思路构树(平衡二叉树完全就是,不过二叉搜索树有些遗憾)。特点:任一节点的权值都大于其左子树上所有点的权值,小于其右子树上所有点的权值。
平衡二叉树:
简介:也是搜索树,不过它改进了:二叉搜索树由于插入顺序的不同,最坏查找次数也不同,运气不好就是O(n).
官方解释:
任一节点的平衡因子的绝对值都不大于1(平衡因子:左子树的高度-右子树的高度。)
这样子由于二叉树的性质查找的时间复杂度就为log(n)了。
今天先展示二叉搜索树的常规操作:创建(也可以当作插入)、查找、删除。
我的代码(有BUG,根节点删除的情况当时没考虑到,所以不要删根节点,不然会段错误)。遍历我是使用的中序非递归(第二次遇到的时候打印)
代码:(有bug多谢指出)

//二叉搜索树的创建(插入)/查找/删除
//二叉搜索树的创建(插入)/查找/删除
#include<stdio.h>
#include<stdlib.h>
typedef struct tree{
    int val;
    struct tree *left,*right;
}tree;
int count = 0;
tree* searchmax(tree *p) {//查找待删除节点左子树的最大值
    tree *q = p;
    while(p->right) {
        q = p;
        p = p->right;
    }
    q->right = NULL;
    if (p->left && p != q) {//最大值左子树非空
        q->right = p->left;
    }
    return p;
}
void create(tree *root,int n) {//暂定都为positive integer,且每个数都unique
    //链表地址发生了改变一定要把改变后的地址赋给上一个节点,因为每个节点存的都是下个节点的地址值而不是地址的地址
    int num;
    tree *p = root;
    scanf("%d",&num);
    root->val = num;
    for (int i = 0;i < n-1;i++) {
        p = root;
        scanf("%d",&num);
        while(p) {
            if (num > p->val) {
                if (p->right == NULL) {
                    p->right = (tree *)malloc(sizeof(tree));
                    p->right->val = num;
                    p->right->left = NULL;
                    p->right->right = NULL;
                    break;
                }
                p = p->right;
            }
            else {
                if (p->left == NULL) {
                    p->left = (tree *)malloc(sizeof(tree));
                    p->left->val = num;
                    p->left->left = NULL;
                    p->left->right = NULL;
                    break;
                }
                p = p->left;
            }
        }
    }
}
tree* search(tree *root,int num) {
    tree *p = root;
    tree *q;
    while (p) {
        if (p->val > num) {
            q = p;
            p = p->left;
        }
        else if (p->val < num){
            q = p;
            p = p->right;
        }
        else {
            count++;
            break;
        }
        count++;
    }
    if (p) {//返回值为该节点的上一个节点(为了下面的删除方便,查找和删除使用同一个模块了,所以下面大部分的q节点都代表待删除的节点的上一个节点)
        return q;
    }
    else {
        return NULL;
    }
}
void delete(tree *root) {
    int num,flag = 0;
    printf("请输入待删除的数字:\n");
    scanf("%d",&num);
    tree *q = search(root,num);
    /*fprintf(stderr,"%d",q->val);*/
    tree *p;
    if (q->left && q->left->val == num) {
        p = q->left;
        flag = 1;
    }
    if (q->right && q->right->val == num) {
        p = q->right;
        flag = 2;
    }
    if (p->left == NULL && p->right == NULL) {//左右子树都为空
        free(p);
        if (flag == 1) {
            q->left = NULL;
        }
        else if (flag == 2) {
            q->right = NULL;
        }
    }
    else if (p->left && p->right == NULL) {//左子树非空,右子树空
        if (flag == 1) {
            q->left = p->left;
            free(p);
        }
        else if (flag == 2) {
            q->right = p->left;
            free(p);
        }
    }
    else if (p->right && p->left == NULL) {//右子树非空,左子树空
        if (flag == 1) {
            q->left = p->right;
            free(p);
        }
        else if (flag == 2) {
            q->right = p->right;
            free(p);
        }
    }
    else {//左右子树都不空,此处采用:左子树的最大值来替换该点
        tree *maxleft = searchmax(p->left);//最大值点
        if (flag == 1) {
            q->left = maxleft;
        }
        else if (flag == 2) {
            q->right = maxleft;
        }
        if (maxleft != p->left) {
            maxleft->left = p->left;
        }
        maxleft->right = p->right;
        free(p);
    }
}
void inorder(tree *root,int n) {//非递归中序遍历:第二次路过该点时打印
    tree *p = root;
    tree *a = (tree *)calloc(n,sizeof(tree));
    int top = 0;
    while(top >= 0) {
        while(p) {
            a[top++] = *p;
            p=p->left;
        }
        if (top >= 0) {
            if (top == 0) {
                break;
            }
            tree out = a[top-1];
            printf("->%d<-",out.val);
            p = out.right;
            top--;
        }
    }
}
int main() {
    tree *root = (tree*)malloc(sizeof(tree));
    root->left = NULL;
    root->right = NULL;
    int n;
    printf("请输入二叉数总数:\n");
    scanf("%d",&n);
    printf("请按插入顺序输入:\n");
    create(root,n);
    printf("中序遍历为:\n");
    inorder(root,n);
    /*fprintf(stderr,"haha");*/
    int num;
    printf("请输入需要查找的数字:\n");
    scanf("%d",&num);
    search(root,num);
    if (count) {
        printf("查到了,查找次数为:%d\n",count);
    }
    else {
        printf("没查到\n");
    }
    delete(root);
    /*fprintf(stderr,"haha");*/
    printf("删除后的树:\n");
    inorder(root,n);
    return 0;
}

在这里插入图片描述

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!