精华内容
下载资源
问答
  • 二叉检索树

    2018-01-03 17:48:33
    使用C++实现实现一个二叉检索树,数据结构与算法的相关内容
  • 二叉检索树 c++数据结构 对应于数据机构与算法分析(c++版)第三版或第二版 Clifford A.Shaffer 重庆大学使用教材
  • 最优二叉检索树问题 二叉检索树是二叉树当中经典的应用之一,广泛应用于实际生活的检索当中。如何构建一棵二叉树使得检索时的平均代价最低即构建最优二叉检索树,是一个问题。通过动态规划的思想可以对其进行解决。 ...

    最优二叉检索树问题

    二叉检索树是二叉树当中经典的应用之一,广泛应用于实际生活的检索当中。如何构建一棵二叉树使得检索时的平均代价最低即构建最优二叉检索树,是一个问题。通过动态规划的思想可以对其进行解决。

    问题描述

    给定n个结点,构造一棵二叉检索树,使得检索的代价最低,即最优二叉检索树。

    分析设计

    二叉检索树的原理、特点、概念及代价在这里不再论述和证明,默认为已知。

    要想使二叉检索树的检索代价最低,就是要使二叉树的**高度最小化。**因此我们就要选择合适的节点作为根节点。

    利用动态规划的思想解决这个问题,我们首先要找到能划分的子问题,即节点减少时的二叉检索树。因此最优二叉检索树一定具有最优子结构的特征,去除根节点的剩下的部分任然是最优二叉检索树。

    C(i,j)C(i,j)表示包含i…j节点的数的搜索代价,设这棵树的根节点为r,对应的左右子树分别是 i…r-1 和 r+1…j,它们对应的叶子分别为 i-1…dr-1和 r…j。树就构造完了,分为两种情况

    1. 只有一个叶子组成的子树 j=i-1, 只有i-1, 那么C(i,j)=qi1C(i,j)= q_i-1 这个子树为1个叶节点 不再划分左右子树;
    2. 子树还包含关键字 即继续划分左右子树 iji\leq j。那么C(i,j)=min[C(i,r1)+C(r+1,j)+w(i,j)]C(i ,j)= min[C(i, r-1) + C(r+1,j) + w(i,j) ] 以r为根的代价中最小值,,即最优二叉检索树。

    源代码

    #include <iostream>
    
    
    using namespace std;
    
    //叶子结点
    struct Leaf {
    	int num;				//叶子的值
    	double probability;		//叶子的概率
    };
    
    void OptimalBST(Leaf l[], int n, double **c, double **r) {
    	double minval, sum;
    	int kmin;
    	//初始化树
    	for (int i = 1; i < n + 1; i++) {
    		c[i][i - 1] = 0;
    		c[i][i] = l[i].probability;
    		r[i][i] = i;
    	}
    	c[n + 1][n] = 0;
    	for (int i = 1; i <= n - 1; i++) {
    		for (int j = 1; j + i <= n; j++) {
    			minval = INT_MAX;
    			for (int k = j; k <= j + i; k++) {
    				if (c[j][k - 1] + c[k + 1][j + i] < minval) {
    					minval = c[j][k - 1] + c[k + 1][j + i];
    					kmin = k;
    				}
    			}
    			r[j][j + i] = kmin;
    			sum = 0;
    			for (int s = j; s <= j + i; s++)
    				sum += l[s].probability;
    			c[j][j + i] = minval + sum;
    		}
    	}
    }
    
    void Print(int start, int end, double **r) {
    	if (start <= end) {
    		int i = r[start][end];
    		cout << i << " ";
    		Print(start, i - 1, r);
    		Print(i + 1, end, r);
    	}
    }
    
    int main() {
    	int n;
    	cout << "输入叶子结点个数:";
    	cin >> n;
    	Leaf *l = new Leaf[n + 1];
    	cout << "输入叶子结点信息;";
    	for (int i = 1; i <= n; i++) {
    		cin >> l[i].probability;
    		l[i].num = i;
    	}
    		
    	double **c = new double*[n + 2];		//主表
    	for (int i = 0; i < n + 2; i++)
    		c[i] = new double[n + 1];
    	double **r = new double*[n + 2];		//根表
    	for (int i = 0; i < n + 2; i++)
    		r[i] = new double[n + 1];
    
    	OptimalBST(l, n, c, r);
    	cout << "该最优二叉检索树的期望为:" << c[1][n] << endl;
    	cout << "中序遍历输出该二叉树:";
    	Print(1,n,r);
    	cout << endl;
    
    	delete []l;
    	for (int i = 0; i < n + 2; i++) 
    		delete[]c[i];
    	delete[]c;
    
    	for (int i = 0; i < n + 2; i++)
    		delete[]r[i];
    	delete[]r;
    	system("pause");
    	return 0;
    }
    

    运行结果

    在这里插入图片描述

    展开全文
  • 二叉检索树的C++实现

    2016-12-20 21:39:05
    二叉检索树

    二叉检索树

    • 属性:对于二叉检索树(Binary Search Tree,BST)的任何一个结点,设其值为K,则该结点左子树中任意一个结点的值都小于K;该结点右字数中任意一个结点的值都大于或等于K。
    • 特点:按照中序遍历将各结点打印出来,就会得到由小到大排列的结点。
      如下图所示:图片描述图片描述
    • 在实现BST之前,首先需要对字典进行定义,字典提供在数据库中存储、查询、删除记录的功能。
      字典的ADT:
    template<typename Key, typename E>
    class Dictionary{
    private:
        void operator =(const Dictionary&){}
        Dictionary(const Dictionary&){}
    public:
        Dictionary(){}
        virtual ~Dictionary(){}
        virtual void clear() = 0;
        virtual void insert(const Key& k, const E& e) = 0;
        virtual E remove(const Key& k) = 0;
        virtual E removeAny() = 0;
        virtual E find(const Key& k) const  = 0;
        virtual int size() = 0;
    };
    • BST的实现:
    template<typename Key, typename E>
    class BST : public Dictionary < Key, E > {
    private:
        BSTNode<Key, E>* root;
        int nodecount;
    
        void clearhelp(BSTNode<Key, E>*);     //清除二叉树
        BSTNode<Key, E>* inserthelp(BSTNode<Key, E>*, const Key&, const E&); //插入函数
        BSTNode<Key, E>* deletemin(BSTNode<Key, E>*);                        //删除最小结点
        BSTNode<Key, E>* getmin(BSTNode<Key, E>*);                           //获取最小结点的值
        BSTNode<Key, E>* removehelp(BSTNode<Key, E>*, const Key&);  //移除函数
        E findhelp(BSTNode<Key, E>*, const Key&) const;     //查找函数
        void printhelp(BSTNode<Key, E>*, int) const;        //打印函数
        public:
        BST()  { root = NULL; nodecount = 0; }      //构造函数
        ~BST() { clearhelp(root); }                    //析构函数
    
        //清除二叉树
        void clear()
        {
            clearhelp(root);
            root = NULL;
            nodecount = 0;
        }
        //插入函数
        void insert(const Key& k,const E& e)
        {
            root = inserthelp(root, k, e);
            nodecount++;
        }
        //移除函数
        E remove(const Key& k)
        {
            E temp = findhelp(root, k);
            if (temp != NULL)
            {
                root = removehelp(root, k);
                nodecount--;
            }
            return temp;
    
        }
        //移除所有元素
        E removeAny()
        {
            if (root != NULL)
            {
                E temp = root->element;
                root = removehelp(root, root->key());
                nodecount--;
                return temp;
            }
            else return NULL;
        }
        //查找元素
        E find(const Key& k) const 
        {
            return findhelp(root, k);
        }
        //返回当前结点的数量
        int size() { return nodecount; }
        //打印二叉树
        void print() const
        {
            if (root == NULL)  cout << "The BST is empty!" << endl;
            else printhelp(root, 0);
        }
    • 查找函数:将字数的根结点及检索的值作为参数,使用递归函数实现。
    template<typename Key, typename E>
    E BST<Key, E>::findhelp(BSTNode<Key, E>* root, const Key& k) const
    {
        if (root == NULL) return NULL;
        if (k < root->key())
            return findhelp(root->left(), k);//查找左边
        else if (k > root->key())
            return findhelp(root->right(), k);//查找右边
        else return root->element();          //找到了
    }
    • 插入函数:要插入一个值K,首先必须要找到它应该放在书机构的什么地方。这样就会把它带到一个叶结点,或者一个在待插入的方向上没有子结点的分支结点。将这个结点即为R,接着,把一个包含K的结点作为R的子结点加上去。
      从根结点到被插入结点的父节点,该路径上的各个结点都被赋予了相应的子结点指针值。
    template<typename Key, typename E>
    BSTNode<Key, E>* BST<Key, E>::inserthelp(BSTNode<Key, E>* root, const Key& k, const E& it)
    {
        if (root == NULL)    //如果为空,则建立一个结点
            return new BSTNode<Key, E>(k, it, NULL, NULL);
        if (k < root->key())
            root->setLeft(inserthelp(root->left(), k, it));
        else 
            root->setRight(inserthelp(root->right(), k, it));
        return root;           //返回被插入结点
    }
    • 由于函数调用了deletemin的缘故,在回到根结点路径上的各个结点的左指针都被重新赋予指向子树。
    template<typename Key, typename E>
    BSTNode<Key, E>* BST<Key, E>::deletemin(BSTNode<Key, E>* rt)
    {
        if (rt->left() == NULL)
        {
            BSTNode<Key, E>* temp = rt->right();
            delete rt;
            return temp->right();
        }
    
        else{
            rt->setLeft(deletemin(rt->left()));
            return rt;
        }
    }
    • 返回二叉树的最小元素的结点
    template<typename Key, typename E>
    BSTNode<Key, E>* BST<Key, E>::getmin(BSTNode<Key, E>* rt)
    {
        if (rt->left() == NULL)
            return rt;
        else return getmin(rt->left());
    }
    • 如果想把一个有两个子结点的结点值删除,只需要对其右字数调用函数deletemin,并用寒素的返回值替代被删除的值。
    template<typename Key, typename E>
    BSTNode<Key, E>* BST<Key, E>::removehelp(BSTNode<Key, E>* rt, const Key& k)
    {
        if (rt == NULL)        //k不在树里
            return NULL;
        //查找所要删除的结点
        else if (k < rt->key())      
            rt->setLeft(removehelp(rt->left(), k));     
        else if (k > rt->key())
            rt->setRight(removehelp(rt->right(), k));
        //找到了,删除
        else
        {
            BSTNode<Key, E>* temp = rt;
            //只有右子结点
            if (rt->left() == NULL)
            {
                rt = rt->right();
                delete temp;
            }
            //只有左子结点
            else if (rt->right() == NULL)
            {
                rt = rt->left();
                delete temp;
            }
            //有两个结点
            else
            {
                BSTNode<Key, E>* t = getmin(rt->right());
                rt->setElement(t->element());
                rt->setKey(t->key());
                rt->setRight(deletemin(rt->right()));
                delete temp;
            }
        }
        return rt;
    }
    • 采用后序遍历进行释放
    template<typename Key, typename E>
    void BST<Key, E>::clearhelp(BSTNode<Key, E>* root)
    {
        if (root == NULL)
            return;
        clearhelp(root->left());
        clearhelp(root->right());
        delete root;
    }
    • 用中序遍历将BST打印出来
    template<typename Key, typename E>
    void BST<Key, E>::printhelp(BSTNode<Key, E>* root, int level) const
    {
        if (root == NULL) return;      //空树
        printhelp(root->left(), level + 1);   //打印左子树
        for (int i = 0; i < level; i++)
            cout << " ";
        cout << root->key() << endl;       //打印结点值
        printhelp(root->right(), level + 1);    //打印右子树
    }
    展开全文
  • 15二叉检索树

    2018-03-05 15:00:00
    二叉检索树(或二叉排序树,二叉有序树)的简称,任一结点a,其左子树中结点的值均小于或等于a,右子树上结点值均大于a(左小右大)。 性质:中序序列是递增的有序序列。 1.检索树的构建方法: 创建一颗空树,...

    检索树

     

    检索树的定义:

    二叉检索树(或二叉排序树,二叉有序树)的简称,任一结点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("\n");
        root = creat(A, n);
        Show(root);
        
        //查询某数值
        printf("\nplease input the search key:");
        scanf("%d", &data);
        if (search(root, data) != NULL) 
            printf("search succed!\n");
        else 
            printf("search failed!\n");
    
        getchar();
        system("pause");
    }

     

    转载于:https://www.cnblogs.com/gd-luojialin/p/8509012.html

    展开全文
  • 二叉检索树(BST)

    千次阅读 2018-10-15 23:00:05
    使用无序表和有序表组织的数据,不是查找时间复杂度偏高,就是插入时间复杂度偏高,而接下来将要介绍的二叉检索树(BST)则能很好的解决以上问题。二叉检索树又称二叉查找树、二叉排序树。 BST性质 BST是满足下面...

    使用无序表和有序表组织的数据,不是查找时间复杂度偏高,就是插入时间复杂度偏高,而接下来将要介绍的二叉检索树(BST)则能很好的解决以上问题。二叉检索树又称二叉查找树、二叉排序树。

    BST性质

    BST是满足下面所给出条件的二叉树:

    对于二叉检索树的任意一个结点,设其值为K,则该结点左子树中任意一个结点的值都小于K;该结点右子树中任意一个结点的值都大于或等于K。

    对于一组数,将这组数的两个排列按规则插入到BST中,如果采用中序遍历将各个结点打印出来,则会得到由小到大排列的相同序列。如下图

    BST实现

    template <typename Key, typename E>
    class BST : public Dictionary<Key, E>
    {
    private:
        BSTNode<Key, E>* root;
        int nodecount;
        
        void clearhelp(BSTNode<Key, E>*);
        BSTNode<Key, E>* inserthelp(BSTNode<Key, E>*, const Key&, const E&);
        BSTNode<Key, E>* deletemin(BSTNode<Key, E>*);
        BSTNode<Key, E>* removehelp(BSTNode<Key, E>*, const Key&);
        E findhelp(BSTNode<Key, E>*, const Key&) const;
        void printhelp(BSTNode<Key, E>*, int) const;
    
    public:
        BST() { root = NULL; nodecount = 0; }
        ~BST() { clearhelp(root); }
        void clear() { clearhelp(root); root = NULL; nodecount = 0; }
        
        void insert(const Key& k, const E& e)
        {
            root = inserthelp(root, k, e);
            nodecount++;
        }
    
        E remove(const Key& k)
        {
            E temp = findhelp(root, k);
            if(temp != NULL)
            {
                root = removehelp(root, k); // 这里有点迷啊,已经找了一次,难道还要找一次???
                nodecount--;
            }
            return temp;
        }
    
        E removeAny()
        {
            if(root != NULL)
            {
                E temp = root->element();
                root = removehelp(root, root->key());
                nodecount--;
                return temp;
            }
            else return NULL;
        }
    
        E find(const Key& k) const { return findhelp(root, k); }
    
        int size() { return nodecount; }
        
        void print() const
        {
            if(root == NULL) cout << "The BST is empty.\n";
            else printhelp(root, 0);
        }
    };
    
    

    注:本例中使用的类BSTNode和DictionaryADT的定义可以参见博主这两篇博文二叉树 线性表(五) 字典

    辅助函数

    1.查找和插入

    template <typename Key, typename E>
    E BST<Key, E>::findhelp(BSTNode<Key, E>* root, const Key& k) const
    {
        if(root == NULL) return NULL;
        if(k < root->key())
            return findhelp(root-left(), k);
        else if(k > root->key())
            return findhelp(root->right(), k);
        else return root->element();
    }
    
    template <typename Key, typename E>
    BSTNode<Key, E>* BST<Key, E>::inserthelp(BSTNode<Key, E>* root, const Key& k, const E& it)
    {
        if(root == NULL)
            return new BSTNode<Key, E>(k, it, NULL, NULL);
        if(k < root->key())
            root->setLeft(inserthelp(root->left(), k, it));
        else root->setRight(inserthelp(root->right(), k , it));
        return root;
    }
    

    2.删除 

    template <typename Key, typename E>
    BSTNode<Key, E>* BST<Key, E>:: deletemin(BSTNode<Key, E>* rt)
    {
        if(rt->left() == NULL)
            return rt->right();
        else
        {
            rt->setLeft(deletemin(rt->left()));
            return it;
        }
    }
    
    template <typename Key, typename E>
    BSTNode<Key, E>* BST<Key, E>:: getmin(BSTNode<Key, E>* rt)
    {
        if(rt->left() == NULL)
            return rt;
        else return getmin(rt->left());
    }
    
    // remove
    template <typename Key, typename E>
    BSTNode<Key, E>* BST<Key, E>:: removehelp(BSTNode<Key, E>* rt, const Key& k)
    {
        if(rt == NULL) return NULL;
        else if(k < rt->key())
            rt->setLeft(removehelp(rt->left(), k));
        else if(k > rt->key())
            rt->setRight(removehelp(rt->right(), k));
        else
        {
            BSTNode<Key, E>* temp = rt;
            if(rt->left() == NULL)
            {
                rt = rt->right();
                delete temp;
            }
            else if(rt->right() == NULL)
            {
                rt = rt->left();
                delete temp;
            }
            else
            {
                BSTNode<Key, E>* temp = getmin(rt->right());
                rt->setElement(temp->element());
                rt->setKey(temp->key());
                rt->setRight(deletemin(rt->right()));
                delete temp;
            }
        }
        return rt;
    }

    删除操作需要分类讨论,被删除的结点记为 rt

    1. 如果 rt 的左子树为空,则只需缩短右侧的树链
    2. 如果 rt 的右子树为空,则只需缩短左侧的树链
    3. 如果 rt 左右子树均存在,这时我们需要考虑用一个原树中的一个元素替换 rt,以保证BST的性质不变

    针对情况3,我们的解决方案是:使用 rt 右子树中的最小结点来替换 rt,这样能保证左子树的所有值都小于根结点,右子树的所有值都大于等于根结点。而我们可以通过getmin()很方便找到右子树中的最小结点。

     

    下面再来讨论一下 rt->setLeft(deletemin(rt->left()));

    看上去每次退出时都要将路径上的所有链重新赋值增加了时间复杂度,但实际上,不仅时间复杂度没有增加,这种做法给编程提供了极大的便利性:这里我们首先要建立一个观念,树的操作总是将cur指针指向根结点的,而子树的根结点虽然还有父结点,但是根结点并不知道自己还有父结点,因为由于树的递归定义,树的操作我们总是采用递归来实现,递归的过程就是通过树链上的“寻路”将我们的树的规模不断的缩小。

    如果我们不在递归"出口处"将 rt 子树的左右结点进行修改,而是在删除结点的递归层进行修改的话,我们并不能知道被删除结点 rt 的父结点,而如果我们像单链表一样对于 rt 的定义进行修改的话,不但程序意图难以理解,而且还需要增加一些特殊情况的处理代码,百害而无一利。

    注:removehelp对于递归返回值和递归出口处的操作的设计十分重要,值得去总结学习

    3.清除和打印

    // postorder
    template <typename Key, typename E>
    void BST<Key, E>:: clearhelp(BSTNode<Key, E>* root)
    {
        if(root == NULL) return;
        clearhelp(root->left());
        clearhelp(root->right());
        delete root;
    }
    
    // inorder
    template <typename Key, typename E>
    void BST<Key, E>:: printhelp(BSTNode<Key, E>* root, int level) const
    {
        if(root == NULL) return;
        printhelp(root->left(), level+1);
        for(int i = 0; i < level; i++)
            cout << " ";
        cout << root->key() << "\n";
        printhelp(root->right(), level+1);
    }

     

    展开全文
  • 最优二叉检索树的概念
  • 最优二叉检索树的算法
  • 最优二叉检索树

    2017-10-01 22:09:26
    定义:平均查找长度最小的二叉检索树,又叫最优二分检索树。 动态规划求解,递推式证明如下: 一个实例:
  • 二叉检索树c语言版

    2012-03-22 16:03:15
    二叉检索树c语言版,有一定量的注释,可以对我我写的C++版。
  • 二叉检索树C++版

    2012-03-13 10:39:14
    二叉检索树C++版,包含了一定的注释,没有采用模板类,仅供参考。
  • 1,二叉搜索定义? (1)每个节点有一个唯一的key值,且所有结点互不相同; (2)左子树所有key值小于根的key值; (3)右子所有key值大于根的key值; (4)左右子树都是二叉搜索。 这就是一棵二叉...
  • 二叉检索树或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也...
  • 是Binary Search Tree code 二叉检索树的代码,实现了插入,删除,检索,遍历,包括先序遍历,中序遍历,后序遍历
  • 二叉检索树 O(log n) - 跳表 O(log n) 理想情况下 数组 O(log n) - 由于有内存局部性原理,数组的查询效率是高于树和跳表的。甚至在小数据的情况下,都有可能数组的移动代价也不高(CPU缓存 + 内存拷贝)。 ...
  • 用动态规划的算法实现最优二叉检索树,使得在检索数据过程中花费的代价最小
  • 分析: 由于是按照y坐标的升序,y坐标向等的按x的升序的顺序给出星星。那么某个星星的等级数就是在他前面x坐标小于等于他的x坐标的星星的个数。...这就是静态二叉检索树 的标准问题了。 #inc...
  • C语言 算法与数据结构 二叉检索树 实现及分析 检索二叉树的创建、判定、和删除 图例分析 源代码 #include<stdio.h> #include<stdlib.h> #include<time.h> /* 检索二叉树的创建、判定、和删除 */ ...
  • 二叉检索树:对于树中的每个节点X,左子树中所有关键字的值小于X的值,右子树中所有关键字的值大于X的值 前序遍历:根节点——>左子树——>右子树 后序遍历:左子树——>右子树——>根节点 中序遍历:左子树——>...
  • 二叉检索树与最大堆的实现代码及验证 验证题目: 1、编写一个能够统计输入文本中所出现的每个单词的词频。 输入:一个文本文件 输出:按照字典顺序将输入文本中出现的单词以及相应的词频排序输出结果 2、重新...
  • 二叉排序的相关操作实现 **********************************/ #include&lt;stdio.h&gt; #include&lt;stdlib.h&gt; typedef struct Node { int data; struct Node *lchild; struct...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 856
精华内容 342
关键字:

二叉检索树