zoukankan      html  css  js  c++  java
  • 15二叉检索树

    检索树

    检索树的定义:

    二叉检索树(或二叉排序树,二叉有序树)的简称,任一结点a,其左子树中结点的值均小于或等于a,右子树上结点值均大于a(左小右大)。

    性质:中序序列是递增的有序序列。

    1.检索树的构建方法:

    创建一颗空树,通过遍历,进行有序插入,按照左小右大的原则。

    检索树的构建算法:

    Bptr  creat( )

       {   Bptr  root;   element_type x;

          root=NULL;  //开始时树为空

          scanf("%d",&x);  //读入元素序列

          while(x!=ZERO)  //ZERO是输入结束标记

              {

              insert(x,root);  //插入x

              scanf("%d",&x);  //读入下一个元素

               }

         return  root;  //构造完毕,返回根结点指针

       }

    2.检索树的查找方法:

    从根结点起,将要找的结点x与当前结点a比较:

    如果遇到空树,表明x不在树中(查找失败)

    若x=a,找到x (查找成功) ;

    若x<a,则递归地查找左子树;

    若x>a,则递归地查找右子树;

    查找算法:

    Bptr  search(element_type x,Bptr p)

       {

         if (p==NULL)

        return  NULL;   //遇到空树

         if (x==p->data)

        return p;  //找到x

       if (x<p->data)

              return search(x, p->Lson); //递归向左

       else

         return  search(x, p->Rson);  //递归向右

       }

    主调语句:  p=search(x,root);

    3. 检索树的插入方法:

    从根结点起,将要插入的元素x与当前的结点比较,

    如果x小于或等于当前结点值,就向左搜索;

    如果x大于当前结点值,就向右搜索;

    直至遇到空结点,就将x作为一片新叶插在这个空

    位置上

    插入算法:

    void  insert(element_type x, Bptr &p)

       {

       if (p==NULL)       //遇到空树

    {

       p=new  Bnode;   //申请新结点

           p->data=x;   //置新结点的值域

           p->Lson=p->Rson=NULL;  //新结点作叶子

           return;    //插入完毕,返回

        } //否则,尚未找到插入点,继续查找.

     if(x<=p->data)

       insert(x,p->Lson);  //递归的向左

    else

       insert(x,p->Rson);   //递归的向右

    }

    主调语句为: insert( x, root);

    检索树的删除方法:

    要点:如何接好断枝,并保持“左小右大”

    大体步骤如下:

    步骤1)先用查找的方法找到要删除的结点x,并记住x的父亲f,再根据下列几种不同情况作出处理。

    步骤2)若x是叶,只要把f指向x的那个链域(Lson或Rson)置空,就删除了x。

    步骤3)若x只有一个儿子,只要将f指向x的那条链域(Lson或Rson)改为指向x的那个唯一的儿子。

    步骤4)若x有两个儿子,就要找到x的中序前驱y,用y代替x,并删除y。这里“代替”指的是将结点y的值域复制到结点x中。

    带监督元结点检索树的删除算法;

    #define  SUCC  1

    #define  NOTFOUND  0

    根结点带带无穷小监督元

    int deleteT(element_type x, Bptr root)

       { 

     Bptr f,p,q,s,r;

        p=NULL;   //p将指向要删除结点

        f=root;    // f的初值指向虚根

        q=root->Rson;  //q搜索指针

     while(q!=NULL)  //循环查找x

     {

           if(x==q->data) 

     {

        p=q;

     q=NULL;} //找到x

         else//没找到x后,继续搜索

         if(x<q->data)

    {

       f=q;

      q=q->Lson;

    }  //向左搜索

         else

     {

      f=q;

      q=q->Rson;

    }    //向右搜索

    }

     if(p==NULL)

       return  NOTFOUND; //没找到x

    // 以下是找到x(p指向x)后的具体删除操作步骤

         if (p->Rson==NULL)  // p无右儿子,用左儿子代替p

         {    if(p==f->Lson)

      {

        f->Lson=p->Lson;

        delete p;

      }

            else

      {

       f->Rson=p->Lson;

      delete p;

      }

    }

    else

    {

      if (p->Lson==NULL)  //p无左儿子,用右儿子代替p

         {

                       if (p==f->Lson)

          {

            f->Lson=p->Rson;

             delete p;

            }

               else

           {

            f->Rson=p->Rson;

            delete p;

            }

    }        

    //以下是p有两个儿子情况的处理

    //p有两个儿子,找p的中序前驱

    else

      { 

    s=p->Lson;   //s是p的左儿子

       if(s->Rson==NULL) //s没有右儿子,用s代替p

       {

       p->data=s->data; //用s的值域代换p的值域

            p->Lson=s->Lson;  //删去s

            delete  s;  

      }

     //以下是s有右儿子的情况

    else

    //s有右儿子,找p的左儿子的最右子孙r

        {  r=s->Rson; 

            while(r->Rson!=NULL)

       {

        s=r;

        r=r->Rson;

      }

            p->data=r->data;  //用r的值域代换p的值域

            s->Rson=r->Lson; //删去r

            delete r;

          }

    }

       return  SUCC; //返回删除成功信息

     }

    二叉检索树的源代码:
    // Bitree.cpp : 定义控制台应用程序的入口点。
    //
    // ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include<stdio.h>
    #include<stdlib.h>
    #include<malloc.h>
    #define MAXSIZE 100
    #define NULL 0
    
    typedef int keytype;
    typedef int elemtype;
    
    typedef struct node
    {
        keytype key;    //关键字域 
        elemtype other;   //其他数据域 
        struct node *lchild, *rchild;        //左右子树
    }bilist;   //二叉检索树的节点结构 
    
    
    bilist * insert(bilist *t, bilist*s)   /* 将*s结点插入到一棵二叉检索树*r中*/
    {
        bilist *f=NULL;            //双亲结点的指针
        bilist *p=NULL;            //临时指针
        p = t;
        while (p != NULL)
        {
            f = p;
            if (s->key == p->key)  //该数值已存在
                return t;
    
            //若该数值小于根结点,遍历左子树,否则遍历右子树
            if (s->key<p->key)        
                p = p->lchild;
            else 
                p = p->rchild;
    
        }
        //建树失败
        if (t == NULL)   
            return s;
        //若该数值小于双亲结点,作为左孩子,否则作为右孩子
        if (s->key<f->key) 
            f->lchild = s;
        else 
            f->rchild = s;
        return t;
    }
    
    
    
    bilist *creat(keytype r[], int n)  //二叉检索树的构造函数算法 
    {
        int i;
        bilist *s, *t;
        t = NULL;
        for (i = 0; i<n; i++)
        {
            s = (bilist *)malloc(sizeof(bilist));        //动态分配字节为bilist的内存空间
            s->key = r[i];                                //把数组的元素存入新结点
            
            s->other = NULL;
            s->lchild = NULL;
            s->rchild = NULL;
            //insert(&t,s);
    
            t = insert(t, s);                        
        }
        return t;
    }
    
    
    /*
    int search(bilist *t,keytype k)  //二叉检索树算法      递归算法
    {
    if((t==NULL) || (t->key==k)) return t;
    else if(t->key<k) return(search(t->rchild,k));
    else return(search(t->lchild,k));
    }
    */
    
    
    int search(bilist *t, keytype k)  /*二叉检索树检索算法*/
    {
        while (t != NULL)
        {
            //寻找到了,返回该数值
            if (t->key == k) 
                return t->key;
            //若根结点大于查询数,遍历左子树,否则遍历右子树
            if (t->key>k) 
                t = t->lchild;
            else 
                t = t->rchild;
        }
    
        return -1;
    }
    
    
    //中序输出整棵二叉树
    void Show(bilist *t)
    {
        if(t!=NULL)
        {
            Show(t->lchild);
            printf("%d ",t->key);
            Show(t->rchild);
            }
    };
    
    int main()
    {
        keytype A[MAXSIZE];
        int i, data, n = 11;
        
        bilist *root;            //实例化一个对象
        for (i = 0; i<n; i++)
        {
            scanf("%d", &A[i]);
        }
        
        printf("
    ");
        root = creat(A, n);
        Show(root);
        
        //查询某数值
        printf("
    please input the search key:");
        scanf("%d", &data);
        if (search(root, data) != NULL) 
            printf("search succed!
    ");
        else 
            printf("search failed!
    ");
    
        getchar();
        system("pause");
    }
  • 相关阅读:
    CSS伪元素:before/CSS伪元素:before/:after content 显示Font Awesome字体图标:after content 显示Font Awesome字体图标
    window.requestAnimationFrame
    HTML5 canvas clearRect() 方法
    canvas save()和canvas restore()状态的保存和恢复使用方法及实例
    git -分支管理(创建、推送、删除)
    微信小程序设置域名、不校验域名
    微信小程序访问豆瓣api403问题解决方发法
    干货:Vue粒子特效(vue-particles插件)
    chmod命令详细用法
    Python新式类和旧式类的区别
  • 原文地址:https://www.cnblogs.com/gd-luojialin/p/8509012.html
Copyright © 2011-2022 走看看