zoukankan      html  css  js  c++  java
  • 二叉排序树

    二叉排序树

    二叉排序树是为了实现数据的有序排列,并可方便的对树中的数据进行插入和删除操作,提高查找效率。

    二叉树

    性质:

    • 若它的左子树不为空,则左子树上的所有值均小于根结点的值
    • 若它的右子树不为空,则右子树上的所有值均大于根结点的值
    • 它的左右子树也分别为二叉排序树

    下面说说二叉排序树的查找,插入,删除操作实现。

    二叉排序树的结点结构:

    template<class T>
    class BTNode
    {
    public:
        //数据域
        T data;
        //指针域
        BTNode<T> *lchild,*rchild;
    public:
        //构造函数
        BTNode(T D,BTNode<T> *l = NULL,BTNode<T> *r=NULL) : data(D),lchild(l),rchild(r) {}
    };
    

    查找

    二叉排序树是一个有序的二叉树,其左子树永远比根节点的值小,右子树用于比根节点的值大。因此我们可以使用递归技术,如果key<p->data,则在p的左子树里面继续寻找;若key>p->data则在p的右子树里面继续寻找;直到key=p->data;否则表示未搜索到,退出函数。实现过程如下图:

    查找

    代码实现

    /*
    1、在rt中递归查找key是否存在,若不存在返回false
    2、f指向rt结点的双亲,若rt为根节点,则f=NULL
    3、若key存在,则返回true,p指向该数据值为key的结点
    4、若key不存在,返回false,p指向访问的最后一个节点
    */
        bool SearchBST(BTNode<T> *rt, T key, BTNode<T> *&p = NULL, BTNode<T> *f = NULL)
        {
            if (!rt) //查找失败
            {
                p = f;
                return false;
            }
            else if (key == rt->data) //查找成功
            {
                p = rt;
                return true;
            }
            else if (key > rt->data)
            {
                return SearchBST(rt->rchild, key, p, rt); //在右子树继续查找
            }
            else
            {
                return SearchBST(rt->lchild, key, p, rt); //在左子树继续查找
            }
        }
    

    收获:函数的参数列表若有指针,并且调用函数时,用的就是一个指针进行传递,则进行的是值传递。而*&a可以避免这种现象,这时进行的是地址传递。

    插入

    插入的关键是,在插入元素后还要继续保持二叉树的有序性。实现过程如下图:

    插入

    代码实现:

    /*
    1、先搜索二叉树rt中是否存在值key
    2、若存在则返回false,不存在则插入
    */
        bool Insert(BTNode<T> *&rt, T key)
        {
            BTNode<T> *p = NULL;
            if (!this->SearchBST(rt, key, p))//未存在key
            {
                BTNode<T> *s = new BTNode<T>(key, NULL, NULL);
                if (!p)//p为空,即根节点为空
                {
                    rt = s;//令根结点等于s
                }
                else if (key < p->data)
                {
                    p->lchild = s;//key小于p->data,将p的左孩子置为s
                }
                else
                {
                    p->rchild = s;//key大于p->data,将p的右孩子置为s
                }
                return true;
            }
            else
            {
                return false;
            }
        }
    

    删除

    二叉排序树的难点是删除操作。

    删除结点分三种情况:

    • 结点没有左右孩子;
    • 结点只有左子树或右子树;
    • 结点左右子树均有;

    结点没有左右孩子:

    解决办法:删除该结点,将该结点的双亲指针域置为NULL

    结点只有左子树或右子树:

    解决办法:删除该结点,将该结点的双亲指针域指向该结点的左子树或右子树。

    结点左右子树均有:

    解决办法:保留该结点,将该结点的数据域改为该结点直接前驱(或直接后继)结点的值,删除该结点的直接前驱结点。

    实现过程如下图:

    删除

    代码实现:

    /*
    若二叉树rt中存在key,在删除结点,并返回true,否则返回false
    */    
    	bool DeleteBST(BTNode<T> *&rt,T key)//地址传递
        {
            if(!rt)
            {
                //未找到
                return false;
            }
            else
            {
                if(rt->data==key)
                {
                    //找到key
                    return Delete(rt);//rt只是其双亲指针域的一个别名
                }
                else if (rt->data>key)
                {
                    return DeleteBST(rt->lchild,key);
                }
                else
                {
                    return DeleteBST(rt->rchild,key);
                }
            }
        }
    

    Delete函数实现:

        bool Delete(BTNode<T> *&p)//地址传递,p只是别名
        {
            BTNode<T> *q;
            //只存在右子树,或右子树也不存在
            if(!p->lchild)
            {
                q=p;
                p=p->rchild;//重接其右子树
                delete q;//删除原来的结点
            }
            //只存在左子树
            else if (!p->rchild)
            {
                q=p;
                p=p->lchild;
                delete q;
            }
            //左右子树均存在
            else
            {
                BTNode<T> *s=p;
                q=p->lchild;
                //寻找其直接前驱结点
                while(q->rchild)
                {
                    s=q;//s为q的双亲
                    q=q->rchild;
                }
                //将q的值赋给p
                p->data=q->data;
                if(s!=p)//若p和q的双亲指向不等
                {
                    s->rchild=q->lchild;//重接s的右子树
                }
                else
                {
                    s->lchild=q->lchild;//重接s的左子树
                }
                delete q;            
            }
            return true;
        }
    

    C++代码实现:

    #include <iostream>
    using namespace std;
    
    //二叉树结点
    template <class T>
    struct BTNode
    {
        T data;                     //存储数据
        BTNode<T> *lchild, *rchild; //左右孩子指针
        BTNode(T D, BTNode<T> *l = NULL, BTNode<T> *r = NULL) : data(D), lchild(l), rchild(r) {}
    };
    
    //二叉树
    template <class T>
    class BST
    {
        //属性值
    private:
        //根节点指针
        BTNode<T> *root;
        //查找结点
        bool SearchBSTP(BTNode<T> *rt, T key, BTNode<T> *&p = NULL, BTNode<T> *f = NULL)
        {
            if (!rt) //查找失败
            {
                p = f;
                return false;
            }
            else if (key == rt->data) //查找成功
            {
                p = rt;
                return true;
            }
            else if (key > rt->data)
            {
                return SearchBSTP(rt->rchild, key, p, rt); //在右子树继续查找
            }
            else
            {
                return SearchBSTP(rt->lchild, key, p, rt); //在左子树继续查找
            }
        }
        //插入结点
        bool Insert(BTNode<T> *&rt, T key)
        {
            BTNode<T> *p = NULL;
            if (!this->SearchBSTP(rt, key, p))
            {
                BTNode<T> *s = new BTNode<T>(key, NULL, NULL);
                if (!p)
                {
                    rt = s;
                }
                else if (key < p->data)
                {
                    p->lchild = s;
                }
                else
                {
                    p->rchild = s;
                }
                return true;
            }
            else
            {
                return false;
            }
        }
        //删除结点
        bool Delete(BTNode<T> *&p)
        {
            BTNode<T> *q;
            if(!p->lchild)
            {
                q=p;
                p=p->rchild;
                delete q;
            }
            else if (!p->rchild)
            {
                q=p;
                p=p->lchild;
                delete q;
            }
            else
            {
                BTNode<T> *s=p;
                q=p->lchild;
                while(q->rchild)
                {
                    s=q;
                    q=q->rchild;
                }
                p->data=q->data;
                if(s!=p)
                {
                    s->rchild=q->lchild;
                }
                else
                {
                    s->lchild=q->lchild;
                }
                delete q;            
            }
            return true;
        }
    
        bool DeleteBSTP(BTNode<T> *&rt,T key)
        {
            if(!rt)
            {
                //未找到
                return false;
            }
            else
            {
                if(rt->data==key)
                {
                    //找到key
                    return Delete(rt);
                }
                else if (rt->data>key)
                {
                    return DeleteBSTP(rt->lchild,key);
                }
                else
                {
                    return DeleteBSTP(rt->rchild,key);
                }
            }
        }
        //中序遍历
        void InOrder(BTNode<T> *rt)
        {
            if(rt)
            {
                InOrder(rt->lchild);
                cout<<rt->data<<" ";
                InOrder(rt->rchild);
            }
        }
        //删除二叉树
        void Destory(BTNode<T> *&rt)
        {
            if(rt)
            {
                Destory(rt->lchild);
                Destory(rt->rchild);
                delete rt;
            }
        }
        //行为属性
    public:
        //构造函数
        BST(BTNode<T> *r = NULL) : root(r) {}
        //拷贝构造函数
        BST(const BST<T> &bt) : root(NULL)
        {
        }
        //删除二叉树
        void Destory()
        {
            this->Destory(this->root);
            this->root=NULL;
        }
        //析构函数
        ~BST()
        {
            this->Destory();
        }
        //获得根指针
        BTNode<T> *Getroot()
        {
            return this->root;
        }
        //搜索值
        //并将
        bool SearchBST(T key, BTNode<T> *p = NULL)
        {
            return this->SearchBSTP(this->root, key, p, NULL);
        }
        //插入结点,顺序插入
        /*1、先判断此值是否存在,若存在,则返回true
          2、若不存在,创造结点s,并顺序插入二叉树中
          3、若不存在,则存在指针p指向查找路径的最后一个结点
          4、判断插入值和指针p指向的值的大小,若key>p->data,则p->rchild=s;
                                          否则p->lchild=s;
        */
        bool InsertBST(T key)
        {
            return this->Insert(this->root, key);
        }
        //shanchujiedian
        bool DeleteBST(T key)
        {
            return this->DeleteBSTP(this->root, key);
        }
    
        void InOrder()
        {
            this->InOrder(this->root);
        }
    };
    
    int main()
    {
        BST<int> temp;
        int a[] = {62,58,88,47,73,99,35,51,93,29,37,49,56,36,48,50};
        for (int i = 0; i < 16; i++)
        {
            temp.InsertBST(a[i]);
        }
        temp.InOrder();
        cout<<endl;
        //BTNode<int> *p;
        cout << "查找结果:" << temp.SearchBST(51) << endl;
        temp.DeleteBST(62);
        cout << "查找结果:" << temp.SearchBST(50) << endl;
        temp.InOrder();
        cout<<endl;
        temp.Destory();
        temp.InOrder();
        cout<<endl;
    
        system("pause");
        return 0;
    }
    
  • 相关阅读:
    linux常用命令
    mysql 开发基础系列20 事务控制和锁定语句(上)
    sql server 性能调优之 资源等待 CXPACKET
    mysql 开发基础系列19 触发器
    mysql 开发基础系列18 存储过程和函数(下)
    mysql 开发基础系列17 存储过程和函数(上)
    sql server 性能调优之 资源等待PAGEIOLATCH
    mysql 开发基础系列16 视图
    mysql 开发基础系列15 索引的设计和使用
    sql server 性能调优之 当前用户请求分析 (1)
  • 原文地址:https://www.cnblogs.com/cqy-wt1124/p/12818809.html
Copyright © 2011-2022 走看看