C语言实现二叉查找树(搜索树)的创建,插入,查找,删除

最近在学习二叉树,看了下网上关于二叉查找树(搜索树)的创建,插入,查找,删除的代码都是一些零碎的代码,在这给出可以运行的完整C代码,并给出写代码过程遇到问题的一些注释,便于大家学习理解二叉查找树(搜索树)的创建,插入,查找,删除。

先来介绍下二叉查找树(搜索树)

二叉查找(搜素)树是满足以下条件的二叉树:1.左子树上的所有节点值均小于根节点值,2右子树上的所有节点值均不小于根节点值,3,左右子树也满足上述两个条件。

  二叉查找树的插入过程如下:1.若当前的二叉查找树为空,则插入的元素为根节点,2.若插入的元素值小于根节点值,则将元素插入到左子树中,3.若插入的元素值不小于根节点值,则将元素插入到右子树中。

  二叉查找树的删除,分三种情况进行处理:

  1.p为叶子节点,直接删除该节点,再修改其父节点的指针(注意分是根节点和不是根节点)。

  2.p为单支节点(即只有左子树或右子树)。让p的子树与p的父亲节点相连,删除p即可;(注意分是根节点和不是根节点)。

  3.p的左子树和右子树均不空。找到p的后继y,因为y一定没有左子树,所以可以删除y,并让y的父亲节点成为y的右子树的父亲节点,并用y的值代替p的值;或者方法二是找到p的前驱x,x一定没有右子树,所以可以删除x,并让x的父亲节点成为y的左子树的父亲节点。

完整代码如下:

/*
*二叉查找树(二叉搜索树)的创建,插入,查找,删除 
*/
#include<stdio.h>
#include<stdlib.h>
struct tnode
{
    int data;
    struct tnode *lchild;
    struct tnode *rchild;
};
struct tnode * tree_insert(struct tnode *root,int data)//插入二叉搜索树的节点 
{
    struct tnode *s;
    //构造要插入的节点
    s=(struct tnode *)malloc(sizeof(struct tnode));
    s->data=data;
    s->lchild=NULL;
    s->rchild=NULL;
    if(root==NULL)
    {
        root=s;
    } 
    else
    {
        if(root->data==s->data)
            return root;
        else
        {
            if(s->data>root->data)
                //tree_insert(root->rchild,s->data); 这样写是错误的,因为不能将根节点和子节点连接在一块。 仔细想一下递归过程。 
                root->rchild=tree_insert(root->rchild,s->data);
            else
                //tree_insert(root->lchild,s->data); 这样写是错误的,因为不能将根节点和子节点连接在一块。
                root->lchild=tree_insert(root->lchild,s->data);
        }
    }
    return root;
}
void tree_scaner(struct tnode *root)
{
    if(root==NULL)
        return;
    
//	printf("%d ",root->data);
    tree_scaner(root->lchild);
    printf("%d ",root->data);
    tree_scaner(root->rchild);
}
int tree_search(struct tnode* root,int data)
{
    if(root==NULL)
        return 0; //return -1程序出错,if语句认为-1不是FALSE。而0是FALSE。 
    else
    {
        if(root->data==data)
            return 1;
        else if(root->data<data)
            return tree_search(root->rchild,data);
        else
             return tree_search(root->lchild,data);
            
    }
    //return 0; 
}

int tree_delete(struct tnode* root,int data)
{
    struct tnode *p,*pf,*t,*s,*sf;
    //找到要删除的节点 
    t=root;
    int flag=0; 
    if(t->data==data)
    {
        p=root;
        flag=1;
    }
    //出现的一个错误,就是下面的while循环里面,全都是if,而不是if-else,这样是不对的,因为程序的本意是一次循环只执行三种情况的一种。 
    while(t!=NULL)  
    {
        if(t->data>data)
        {
            pf=t;
            t=t->lchild;
        }
        else if(t->data<data)
        {
            pf=t;
            t=t->rchild;
        }
        else if(t->data==data)
        {
            p=t;
            flag=1;
            break;
        }
    }
    //找到要删除的节点
    
    //根据三种不同情况删除节点
    if(flag==0)
    {
        printf("this node not in the tree!");
    } 
    //出现的一个错误,三种情况全用if,而不是if-else,这样是不对的,因为程序的本意是一次循环只执行三种情况的一种。 
    if(p->lchild==NULL&&p->rchild==NULL)
    {
        if(p==root)
        {
            root=NULL;
        }
        else
        {
            //不能这样写<span style="font-family: Arial, Helvetica, sans-serif;">p=NULL;</span>
            if(pf->lchild==p)
                pf->lchild=NULL;
            else
                pf->rchild=NULL;//体会这两种写法的不同。 
        }
    }
    else if((p->lchild==NULL&&p->rchild!=NULL)||(p->lchild!=NULL&&p->rchild==NULL))
    {
        if(p==root)
        {
            if(p->lchild==NULL) 
                root=p->rchild;
            else
                root=p->lchild;
        }
        else
        {
            if(p->lchild==NULL) 
            {
                if(pf->rchild==p)
                {
                    pf->rchild=p->rchild;
                }
                else
                {
                    pf->lchild=p->rchild;
                }
            }
            else
            {
                if(pf->rchild==p)
                {
                    pf->rchild=p->lchild;
                }
                else
                {
                    pf->lchild=p->rchild;
                }
            }
        }
    }
    
    else if(p->lchild!=NULL&&p->rchild!=NULL)
    {
        s=p->rchild;
        while(s->lchild!=NULL)
        {
            sf=s;
            s=s->lchild;
        }//纠结的部分,找到p的直接后继 
        p->data=s->data;
        sf->lchild=s->rchild;
    } 
    
}
int main()
{
    struct tnode *root;
    int data,i;
    int tree[12]={15,16,20,18,23,5,12,13,3,10,6,7};
//	root=(struct tnode *)malloc(sizeof(struct tnode));
//构建二叉搜索树 
    root=NULL;//need or not?必须要赋NULL值,因为当节点为空时就把改节点当成根节点。 
    //while(scanf("%d",&data)!=EOF)
    for(i=0;i<12;++i)
    {
        printf("....\n");
        data=tree[i];
        root=tree_insert(root,data);
    }
    //构建二叉搜索树
    tree_scaner(root);//遍历二叉搜索树 
    //在二叉搜索树种查找某个节点
    printf("input key:");
    scanf("%d",&data);
    if(tree_search(root,data)) 
    {
        printf("yes\n");
    }
    else
    {
        printf("failed\n");
    }
    printf("delete key:");
    scanf("%d",&data);
    tree_delete(root,data);
    tree_scaner(root);
}

程序可能不是最简洁的,但便于学习和理解,由于时间有限没做太多的测试,欢迎大家指出其中的错误。

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/ahfytao/article/details/40183683
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞