数据结构与算法分析--二叉排序树(二叉查找树,二叉搜索树)的查找、插入和删除操作

  • 什么是二叉排序树
    它表示一棵二叉树,并且包含以下性质:
    1)可能是一棵空树
    2)若不为空,那么其左子树结点的值都是小于根结点的值,右子树结点的值都是大于根结点的值
    3)左右子树都是二叉树。

  • 对于二叉排序树功能的介绍
    本文主要介绍的是二叉排序树的几种基本操作,包括查找、插入和删除操作。用到的二叉排序树如下图所示:
    二叉排序树

  • 二叉排序树的建立
  • 二叉树结点的创建:
typedef struct BiTNode
{
    int data;
    struct BiTNode *lchild,*rchild,*parent;
}BiTNode,*BiTree;
  • 二叉排序树的创建过程
    二叉排序树的创建过程。主要包含两个部分:二叉排序树的创建和插入每个结点的过程。主要就是利用递归操作插入结点。具体过程如下:
    • 申请一个结点p的空间,存储数据和左右子树的指针。
  • 几种情况的判断:
  • 1.判断是否为空树,空树时,插入的节点直接为根结点
  • 2.插入结点的值>根结点的值,插入结点直接设置为右孩子。设置方式:根结点的右孩子子针直接连接插入结点。
  • 3.插入结点的值<根结点的值,插入结点直接设置为左孩子。设置方式 : 根结点的左孩子子针直接连接插入结点。
  • 4.进行递归操作。继续插入下个结点,此时的根结点就是刚刚插入的结点。
//创建一棵二叉排序树
void create(BiTree* root,int* keyArray,int length )
{
    int i;
    for(i=0;i<length;i++)
        insert(root,keyArray[i]);
}
//插入每个结点
void insert(BiTree* root,int data)
{
    //初始化插入的节点
    BiTree p=(BiTree)malloc(sizeof(BiTNode));
    p->data=data;
    p->lchild=p->rchild=NULL;
    //空树时,直接最为根结点
    if((*root)=NULL)
    {
        *root=p;
        return;
    }
    //插入到当前结点的左孩子
    if((*root)->lchild==NULL&&(*root)->data>data)
    {
        p->parent=(*root);
        (*root)->lchild=p;
        return;
    }
    if((*root)->rchild==NULL&&(*root)->data<data)
    {
        p->parent=(*root);
        (*root)->rchild=p;
        return;
    }
    if((*root)->data>data)
        insert(&(*root)->lchild,data);
    else if((*root)->data<data)
        insert(&(*root)->rchild,data);
    else
        return;
}

-二叉排序树的搜索和插入操作
二叉排序树的搜索过程:

  • 二叉树是否存在
  • 搜索结点的值是否等于T的值
  • 如果搜索结点的值小于T的值,那就进行递归操作继续搜索T的左子树。
  • 如果搜索结点的值大于T的值,那就进行递归操作继续搜索T的右子树。

二叉排序树的插入操作主要包括以下几个过程:

  • 1.首先判断插入结点,和树中结点是否存在重复,这时候用到的是结点的搜索操作,若没有重复的节点,就进行后面的插入操作。
  • 2.创建一个新结点,存储插入结点的值。
  • 3.如果是空树,插入结点直接插入进去。
  • 4.如果树不为空,插入结点的值小于最后一个结点的值,插入结点连接最后一个结点的左子树;插入结点的值大于最后一个结点的值,插入结点连接最后一个结点的右子树。
 /*
当二叉排序树T中不存在关键字key的数据元素时,插入key并返回true,否则返回false.
*/
BiTree SearchBST(BiTree T,int key,BiTree f,BiTree * p)
{
    if(!T)
    {
        *p=f;
        return NULL;
    }
    else if(key==T->data)
    {
        *p=T;
        return *p;
    }
    else if(key<T->data)
    {
        return SearchBST(T->lchild,key,T,p);
    }
    else
        return SearchBST(T->rchild,key,T,p);
}
BiTree InsertBTS(BiTree *T ,int key)
{
    BiTree p,s;
    //判断经过二叉树的查找,是否找得到所需结点
    if(!SearchBST(*T,key,NULL,&p))
    {
        //找不到结点,那首先生成一个结点(不存在重复结点)
        s=(BiTree)malloc(sizeof(BiTNode));
        s->data=key;
        s->lchild=NULL;
        s->rchild=NULL;

        if(!p)//最后一个结点是否在树里面,进入循环表示树不为空,进入查找。
        {
            *T=s;
        }
        if(key<p->data)
        {
            s=p->lchild;
        }
        else
        {
            s=p->rchild;
        }
        return s;
    }
    else
    {
        return NULL;
    }

}

.

查找删除结点操作

  • 判断键值是否等于当前结点的值,等于直接调用删除函数。
  • 如果键值小于当前结点的值,则递归调用查找删除结点,若值小于此结点的值,递归传入左子树,若大于递归传入右子树。

删除操作主要包含三种情况:
定义删除结点为p结点,q指针用于传递。

  • 删除结点的右子树为空的情况下
    把p结点的地址传给q指针,再把p的左子树的值传递给p,最后释放q。
  • 删除结点的左子树为空的情况下
    把p结点的地址传给q指针,再把p的右子树的值传递给p,最后释放q。
  • 删除结点的左右子树都不为空
    这种情况的主要思想是用删除结点的直接前驱去替换这个结点的值,最后只需要释放直接前驱的结点即可,框架结构是不需要调整的。(下面的删除方式是以找到左子树的直接前驱结点为例
    1.q指针指向删除结点的位置,s指针指向删除结点的左子树。
    2.然后循环搜索直接前驱结点,并用s指针指向这个前驱结点,q指向前驱结点的双亲节点。
    3.进行判断,如果删除的结点就是前驱结点的双亲节点,那么直接就把双亲节点替换到前驱结点的位置。如把99替换到100的位置。如果存在前驱结点的子树,那么就把删除结点的左子树连接前驱结点的左子树。例如103放到100的位置上。
    4。最后释放前驱结点。
BiTree Delete(BiTree *p)
{
    BiTree q,s;
    //右子树为空的情况下
    if((*p)->rchild==NULL)
    {
        q=*p;
        *p=(*p)->lchild;
        free(q);
    }
    else if((*p)->lchild==NULL)
    {
        q=*p;
        *p=(*p)->rchild;
        free(q);
    }
    //以直接前驱做替换
    else
    {
        q=*p;
        s=(*p)->lchild;
        while(s->rchild)
        {
            q=s;
            s=s->rchild;
        }
        (*p)->data=s->data;
        if(q!=*p)
        {
            q->rchild=s->lchild;
        }
        else
        {
            q->lchild=s->lchild;
        }
        free(s);
    }
    return s;
}

//删除二叉树模块
BiTree DeleteBST(BiTree *T ,int key)
{
    if(!*T)
    {
        return NULL;
    }
    else
    {
        if(key==(*T)->data)
            return Delete(T);

        else if(key<(*T)->data)
        {
            return DeleteBST(&((*T)->lchild),key);
        }
        else
        {
            return DeleteBST(&(*T)->rchild,key);
        }
    }
}
  • 6
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
数据结构与算法分析是计算机科学中非常重要的领域,C语言作为一种广泛应用于系统开发和嵌入式领域的编程语言,也被广泛应用于数据结构与算法的实现。 在C语言中,可以使用数组、链表、栈、队列、堆、树等数据结构来实现各种算法。下面我将简单介绍几种常见的数据结构算法在C语言中的实现: 1. 数组:C语言天生支持数组,可以使用数组来存储一组相同类型的元素。通过下标访问数组元素,可以实现快速的插入删除查找操作。 2. 链表:链表是一种动态数据结构,可以根据需要进行灵活的插入删除操作。在C语言中,可以使用结构体来定义链表节点,通过指针将各个节点连接起来。 3. 栈:栈是一种后进先出(LIFO)的数据结构,可以使用数组或链表来实现。在C语言中,可以使用数组和一个指向栈顶的指针来实现栈操作。 4. 队列:队列是一种先进先出(FIFO)的数据结构,同样可以使用数组或链表来实现。在C语言中,可以使用数组和两个指针(分别指向队列的头和尾)来实现队列操作。 5. 堆:堆是一种特殊的树形数据结构,常用于实现优先队列等应用。在C语言中,可以使用数组来表示堆,并使用相应的算法来维护堆的性质。 6. 树:树是一种非线性数据结构,常用于组织和存储数据。在C语言中,可以使用结构体和指针来实现二叉树二叉搜索树、红黑树等各种类型的树。 对于算法分析和实现,C语言提供了丰富的语法和库函数支持。例如,可以使用递归或迭代的方式实现常见的排序算法(如冒泡排序、插入排序、快速排序等),也可以使用各种搜索算法(如线性搜索、二分搜索等)来查找特定元素。 总之,C语言提供了丰富的工具和语法来实现各种数据结构算法,通过合理地选择和应用它们,可以提高程序的效率和性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值