基于树的查找

二叉排序树

  二叉排序树或者是一颗空树

  若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;

  若它的右子树不空,则右子树上所有节点的值均大于其根节点的值。

  左右子树分别为二叉排序树

存储结构:

typedef struct node
{
    int key;//关键字的值
    struct node *lchild,*rchild;//左右指针
}BSTNode,*BSTree;

二叉排序树插入

算法思想:

  1. 若二叉排序树是空树,则key成为二叉排序树的根
  2. 若二叉排序树是非空空树,则key与二叉排序树的根比较

    a.若果key的值等于根节点的值停止插入

    b.如果key的值小于根节点的值,则将key插入左子树

    c.如果key的值大于根节点的值,则将key插入右子树

//二叉排序树的插入递归算法
void InsertBST(BSTree &bst,int key)
{
    BSTree s;
    if(bst==NULL)//递归结束,也就是找到了叶子结点,申请内存,为此叶子结点插入新元素
    {
        s=(BSTree)malloc(sizeof(BSTNode));
        s->key=key;
        s->lchild=s->rchild=NULL;
        bst=s;
    }
    else if(key<bst->key)//key的值小于根结点的值,插入左子树
        InsertBST(bst->lchild,key);
    else if(key>bst->key)//key的值小于根结点的值,插入右子树
        InsertBST(bst->rchild,key);
}

二叉排序树创建

算法思想:

  首先将二叉排序树初始化为一棵空树,然后逐个读入元素,读入每一个元素就建立一个新的结点,并插入到当前已经生成的二叉排序树中,插入时比较始终是从二叉排序树的根开始的

//创建二叉排序树
void CreateBST(BSTree &bst)
{
    int key;
    bst=NULL;
    scanf("%d",&key);
    while(key!=0)//输入零结束插入
    {
        InsertBST(bst,key);
        scanf("%d",&key);
    }
}

二叉排序树查找

算法思想:

  将关键字key的值与根结点的值比较

  1. key==t,返回跟节点的地址
  2. key<t,进一步查找左子树
  3. key>t,进一步查找右子树
//二叉排序树的查找---递归,查找成功返回该元素的指针,否则返回NULL
BSTree SearchBST(BSTree bst,int key)
{
    if(!bst)
        return NULL;
    else if(bst->key==key)
        return bst;
    else if(bst->key<key)
        return SearchBST(bst->rchild,key);
    else
        return SearchBST(bst->lchild,key);

}
//二叉排序树的查找---非递归,查找成功返回该元素的指针,否则返回NULL
BSTree _SearchBST(BSTree bst,int key)
{
    BSTree t=bst;
    while(t)
    {
        if(t->key==key)
            return t;
        else if(t->key>key)
            t=t->lchild;
        else
            t=t->rchild;
    }
    return NULL;
}

二叉树中找出查找最大最小元素是极简单的事情,从根节点一直往左走,直到无路可走就可得到最小值;从根节点一直往右走,直到无路可走,就可以得到最大值

//查找最小的元素
BSTree SearchMin(BSTree bst)
{
    if(!bst)
        return NULL;
    if(bst->lchild==NULL)
        return bst;
    else
        SearchMin(bst->lchild);
}
//查找最大的元素
BSTree SearchMax(BSTree bst)
{
    if(!bst)
        return NULL;
    if(bst->rchild==NULL)
        return bst;
    else
        SearchMax(bst->rchild);
}

二叉排序树删除

算法思想:

  方法一:

  1. 若p为叶子结点,则可以将其直接删除f->lchild=NULL,free(p);
  2. 若p结点只有左子树或右子树,将p的左子树或右子树直接改为双亲的左子树,f-lchild=p-lchild  or f->lchild=p->rchild;
  3. 既有左子树又有右子树

    a.找到p结点在中序序列中的直接前序s,然后将p的左子树改为f的左子树,p右子树改为s的右子树

    b.找到p结点在中序序列中的直接前序s,用s结点的值代替p结点的值,再将s删除,原s结点的左子树改为s的双亲结点q的右子树。

a方法的代码实例如下

BSTree DelBST(BSTree bst,int key)
{
    BSTree p=bst,f=NULL;
    while(p)
    {
        if(p->key==key)//找到跳出循环,p指向要删除的结点
            break;
        f=p;//f指向p的双亲
        if(p->key>key)
            p=p->lchild;
        else
            p=p->rchild;
    }
    if(p==NULL)//查找失败
        return NULL;

    if(p->lchild==NULL)//p无左子树
    {
        if(f==NULL)//p是原来二叉排序树的根
            bst=p->rchild;
        else if(f->lchild==p) //p是f的左孩子
            f->lchild=p->rchild;
        else//p是f的右孩子
            f->rchild=p->rchild;
        free(p) ;
    }
    else//p有左子树
    {
        BSTree q=p,s=p->lchild;
        while(s->rchild)//p的左子树中找最右下的结点
        {
            q=s;
            s=s->rchild;
        }
        if(q==p)
            q->lchild=s->lchild;//将s的左子树连接到q上
        else
            q->rchild=s->lchild;
        p->key=s->key;
        free(s) ;
    }
    return bst;
}    

方法二:

对于二叉排序树中的节点A,对它的删除分为两种情况:

  1、如果A只有一个子节点,就直接将A的子节点连至A的父节点上,并将A删除

  2、如果A有两个子节点,我们就以右子树内的最小节点取代A

BSTree DelBST(BSTree &bst,int key)
{
    BSTree p=bst,parent=NULL,s=NULL;//bst是要删除的结点 

    if(!p)
        return NULL;

    if(p->key==key)
    {
        if(!p->lchild&&!p->rchild)//叶子结点
            bst=NULL;
        else if(p->lchild&&!p->rchild)//只有左结点
            bst=p->lchild;
        else if(p->rchild&&!p->lchild) //只有右结点
            bst=p->rchild;
        else
        {
            s=p->rchild;//找右子树中最小的结点来代替要删除的结点
            if(!s->lchild)//s无左结点
                s->lchild=p->lchild;//用s的左结点代替p的左结点,然后直接用s直接代替bst
            else//s有左孩子
            {
                while(s->lchild)
                {
                    parent=s;//parent是s的双亲结点
                    s=s->lchild;
                }
                parent->lchild=s->rchild;//因为要用s代替parent,所以要保存下s的左结点的值
                s->lchild=p->lchild;//s的左结点的值代替p左结点的值
                s->rchild=p->rchild;//s右结点的值代替p右结点的值
            }
            bst=s;//s代替p的值
        } 

    }
    else if(p->key<key)
        DelBST(p->rchild,key);
    else if(p->key>key)
        DelBST(p->lchild,key);
}

完整代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct node
{
    int key;//关键字的值
    struct node *lchild,*rchild;//左右指针
}BSTNode,*BSTree;

//二叉排序树的插入递归算法
void InsertBST(BSTree &bst,int key)
{
    BSTree s;
    if(bst==NULL)//递归结束,也就是找到了叶子结点,申请内存,为此叶子结点插入新元素
    {
        s=(BSTree)malloc(sizeof(BSTNode));
        s->key=key;
        s->lchild=s->rchild=NULL;
        bst=s;
    }
    else if(key<bst->key)//key的值小于根结点的值,插入左子树
        InsertBST(bst->lchild,key);
    else if(key>bst->key)//key的值小于根结点的值,插入右子树
        InsertBST(bst->rchild,key);
}

//创建二叉排序树
void CreateBST(BSTree &bst)
{
    int key;
    bst=NULL;
    scanf("%d",&key);
    while(key!=0)//输入零结束插入
    {
        InsertBST(bst,key);
        scanf("%d",&key);
    }
}

//二叉排序树的查找---递归,查找成功返回该元素的指针,否则返回NULL
BSTree SearchBST(BSTree bst,int key)
{
    if(!bst)
        return NULL;
    else if(bst->key==key)
        return bst;
    else if(bst->key<key)
        return SearchBST(bst->rchild,key);
    else
        return SearchBST(bst->lchild,key);

}

//二叉排序树的查找---非递归,查找成功返回该元素的指针,否则返回NULL
BSTree _SearchBST(BSTree bst,int key)
{
    BSTree t=bst;
    while(t)
    {
        if(t->key==key)
            return t;
        else if(t->key>key)
            t=t->lchild;
        else
            t=t->rchild;
    }
    return NULL;
}

//查找最小的元素
BSTree SearchMin(BSTree bst)
{
    if(!bst)
        return NULL;
    if(bst->lchild==NULL)
        return bst;
    else
        SearchMin(bst->lchild);
}
//查找最大的元素
BSTree SearchMax(BSTree bst)
{
    if(!bst)
        return NULL;
    if(bst->rchild==NULL)
        return bst;
    else
        SearchMax(bst->rchild);
}

//删除结点
BSTree DelBST(BSTree &bst,int key)
{
    BSTree p=bst,parent=NULL,s=NULL;//bst是要删除的结点 

    if(!p)
        return NULL;

    if(p->key==key)
    {
        if(!p->lchild&&!p->rchild)//叶子结点
            bst=NULL;
        else if(p->lchild&&!p->rchild)//只有左结点
            bst=p->lchild;
        else if(p->rchild&&!p->lchild) //只有右结点
            bst=p->rchild;
        else
        {
            s=p->rchild;//找右子树中最小的结点来代替要删除的结点
            if(!s->lchild)//s无左结点
                s->lchild=p->lchild;//用s的左结点代替p的左结点,然后直接用s直接代替bst
            else//s有左孩子
            {
                while(s->lchild)
                {
                    parent=s;//parent是s的双亲结点
                    s=s->lchild;
                }
                parent->lchild=s->rchild;//因为要用s代替parent,所以要保存下s的左结点的值
                s->lchild=p->lchild;//s的左结点的值代替p左结点的值
                s->rchild=p->rchild;//s右结点的值代替p右结点的值
            }
            bst=s;//s代替p的值
        } 

    }
    else if(p->key<key)
        DelBST(p->rchild,key);
    else if(p->key>key)
        DelBST(p->lchild,key);
}

//中序遍历二叉树
void InorderSearch(BSTree bst)
{
    if(bst)
    {
        InorderSearch(bst->lchild);
        printf("%d ",bst->key);
        InorderSearch(bst->rchild);
    }
}

int main()
{
    BSTree bst;
    CreateBST(bst);

    int key;
    printf("删除元素之前---请输入要查找的元素:");
    scanf("%d",&key);
    BSTree temp=SearchBST(bst,key);
    if(temp)
        printf("(递归)查找成功,查找的元素是:%d\n",temp->key);
    else
        printf("查找失败.\n");

    BSTree temp1=_SearchBST(bst,key) ;
    if(temp1)
        printf("(非递归)查找成功,查找的元素是:%d\n",temp1->key);
    else
        printf("查找失败.\n");

    BSTree temp2=SearchMin(bst);
    if(temp2)
        printf("最小的元素是:%d\n",temp2->key);
    else
        printf("最小的元素查找失败.\n");

    BSTree temp3=SearchMax(bst);
    if(temp3)
        printf("最大的元素是:%d\n",temp3->key);
    else
        printf("最大的元素查找失败.\n");

    printf("请输入要删除的值:");
    scanf("%d",&key);
    temp3=DelBST(bst,key);

    printf("中序遍历二叉树:\n");
    InorderSearch(bst);
    printf("\n");
    return 0;
}

原文地址:https://www.cnblogs.com/tianzeng/p/9690533.html

时间: 2024-10-13 02:52:49

基于树的查找的相关文章

基于二叉排序树的查找

导论:首先,沿着二分查找的思路,我们构造一种二叉树来查找,这种二叉树的左子树结点都小于根节点,右子树节点都大于根节点,这样一来,所有结点算是都排好序了,接下来就可以查找 基于二叉排序树的查找 一.二叉排序树的定义 所谓二叉排序树是一个什么样的东西,我们得弄清楚,以下是二叉排序树的定义: 1.若它的左子树非空,则左子树上所有节点的值都小于根节点的值 2.若它的右子树非空,则右子树上所有结点的值都大于根节点的值 3.它的左子树和右子树也是一颗二叉排序树 有了定义,很多东西就都会显而易见了: 1.二叉

hdu 5592 ZYB&#39;s Premutation (线段树+二分查找)

链接: http://acm.hdu.edu.cn/showproblem.php?pid=5592 Problem Description ZYB has a premutation P,but he only remeber the reverse log of each prefix of the premutation,now he ask you to  restore the premutation.Pair (i,j)(i<j) is considered as a reverse

基于数组二分查找算法的实现

基于数组二分查找算法的实现 二分查找 查找 算法 赵振江 二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好:其缺点是要求待查表为有序表,且插入删除困难.因此,折半查找方法适用于不经常变动而查找频繁的有序列表.首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功:否则利用中间位置记录将表分成前.后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表.重复以上过程,直到找到满足条件的记录,使查找成功

B树的查找、插入操作

B树的性质: 根节点至少有两个孩子 每个非根节点有[,M]个孩子 每个非根节点有[-1,M-1]个关键字,并且以升序排列 key[i]和key[i+1]之间的孩子节点的值介于key[i].key[i+1]之间 所有的叶子节点都在同一层 以下代码实现了B树的查找和插入操作,删除操作暂未实现 插入:先找到插入结点的位置,插入后判断关键字的个数是否小于M(M为阶数),小于返回,不小于进行分裂. 删除:任一关键字K的中序前趋(后继)必是K的左子树(右子树)中最右(左)下的结点中最后(最前)一个关键字.

基于快速排序的查找前K个最大数

快速排序 下面是之前实现过的快速排序的代码. function quickSort(a,left,right){ if(left<right){ let mid=partition(a,left,right);//选出key下标 quickSort(a,left,mid-1);//对key的左半部分排序 quickSort(a,mid+1,right)//对key的右半部份排序 } } function partition(a,left,right){ let key=a[left];//一开始

R语言基于树的方法:决策树,随机森林,套袋Bagging,增强树

原文链接:http://tecdat.cn/?p=9859 概观 本文是有关  基于树的  回归和分类方法的.用于分割预测变量空间的分割规则可以汇总在树中,因此通常称为  决策树  方法. 树方法简单易懂,但对于解释却非常有用,但就预测准确性而言,它们通常无法与最佳监督学习方法竞争.因此,我们还介绍了装袋,随机森林和增强.这些示例中的每一个都涉及产生多个树,然后将其合并以产生单个共识预测.我们看到,合并大量的树可以大大提高预测准确性,但代价是损失解释能力. 决策树可以应用于回归和分类问题.我们将

Redis研究-3.3数据结构之树与查找、排序等(后续)

3.树.二叉树.森林之间的转换 前面我们又说到,二叉树中的节点我们可以表示成一个具有左孩子域.右孩子域.双亲域.自身数据域的一个数据结构,那么对于一般的树或者森林中的节点来说,能不能也这样子表示呢?答案是可以的,表示成二叉树节点的形式,我们就能很好的使用二叉树的一些特性和算法. 在二叉树中,left表示节点的左孩子.right表示节点的右孩子,那么,对于一般的树节点来看,如果存在孩子,第一个孩子就是对应的left区域,如果有第二个.第三个孩子等,就用right形成一个链表,那么,这种树就转换为二

Problem C (字典树的查找删除和插入)2016&quot;百度之星&quot; - 资格赛(Astar Round1)

Problem C Accepts: 630 Submissions: 5255 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Problem Description 度熊手上有一本神奇的字典,你可以在它里面做如下三个操作: 1.insert : 往神奇字典中插入一个单词 2.delete: 在神奇字典中删除所有前缀等于给定字符串的单词 3.search: 查询是否在神奇字典中

Redis研究-3.3数据结构之树与查找、排序等

1.树相关的内容 1.1 Tree概念 树是n(n>=0)个节点的有限集.n=0的时候,我们把它叫做空树.在任何一非空树中满足两个特点:(1) 有且只有一个叫做根的节点.(2)n>1时,其余节点可分为m(m>0)个 互不相交的有限集T1,T2,...其中每一个结合本身也是一棵树. 上面的这概念用到了递归的定义. 树的相关概念: 节点的度:是指这个节点的子树的个数. 树的度:是指树的节点中拥有最大多数量的节点的度. 节点的关系:节点的子树的根叫做该节点的 孩子,相应的,该节点成为孩子的 双