基于树的查找

Posted tianzeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于树的查找相关的知识,希望对你有一定的参考价值。

二叉排序树

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

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

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

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

存储结构:

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
",temp->key);
    else
        printf("查找失败.
");
    
    BSTree temp1=_SearchBST(bst,key) ;
    if(temp1)
        printf("(非递归)查找成功,查找的元素是:%d
",temp1->key);
    else
        printf("查找失败.
");
    
    BSTree temp2=SearchMin(bst);
    if(temp2)
        printf("最小的元素是:%d
",temp2->key);
    else
        printf("最小的元素查找失败.
");
        
    BSTree temp3=SearchMax(bst);
    if(temp3)
        printf("最大的元素是:%d
",temp3->key);
    else
        printf("最大的元素查找失败.
");
        
    printf("请输入要删除的值:");
    scanf("%d",&key);
    temp3=DelBST(bst,key);
    
    printf("中序遍历二叉树:
");
    InorderSearch(bst);
    printf("
");
    return 0;
}

 

以上是关于基于树的查找的主要内容,如果未能解决你的问题,请参考以下文章

基于二叉排序树的查找

基于树的查找法

基于树的查找法

二叉树的操作

基于树的查找

次优查找树的原理是什么?