C++算法(一)之二叉查找树

【理论支持】

算法导论第十二章,二叉查找树


【应用】

二叉查找树是一种很常用的数据结构,太经典,必掌握!它支持很多种动态集合操作.

可用作字典,用作优先队列.

基本操作的时间和树高度成正比,时间复杂度为Θ(lgn)


【我们要实现的操作】

search             查找

minMum          返回最小值

maxMum         返回最大值

predecessor     返回结点x的前驱

successor        返回结点x的后继

insert               插入结点x

delete              删除结点x 


【学到的C++基础知识点】

(一)const T& data() const; 定义模版时写的,前后两个const有什么区别,各有什么作用?

(1)前面的const修饰T&
        修饰的目的是,虽然返回的是T的引用,但是返回值不能作为<左值>,也就是对于返回值只能读,不能写
(2)后面那个const说明在data()函数内部,不能以任何方式直接或间接的修改成员变量
        就是说只能读成员变量而不能写...(get from baidu zhidao)

(二)泛型怎么用?

例如:

template <class T>
struct BinaryNode
{
    T                element;
    BinaryNode        *left;
    BinaryNode        *right;
    BinaryNode        *parent;
    BinaryNode(const T& _element,
               BinaryNode *_left,
               BinaryNode *_right,
               BinaryNode *_parent):
        element(_element),
        left(_left),
        right(_right),
        parent(_parent)
    {
    }
};

然后这么使用:BinaryNode<int>* node;

在定义函数的时候,这么使用:

template class<T>

const T& CBinarySearchTree<T>::findMinNum() const
{
     BinaryNode<T>* res = findMinNum(m_Root);
      return res == NULL?NULL:res->element;
}

(三)内存怎么管理

因为不断往树中插入结点,需要insert,自然而然就需要申请内存,怎么申请呢?申请的内存如何释放呢?

(1)申请内存

我们用(二)中的struct BinaryNode来举例,要申请一个BinaryNode的内存空间:用到了构造函数(struct和class都有构造函数)

template class<T>

void CBinarySearchTree<T>::insert(const T& z)

{

//初始化新结点,内存处理...

        BinaryNode<T>* newNode = new BinaryNode<T>(z,NULL,NULL,NULL);

//.....

}

(2)释放内存

在CBinarySearchTree类的析构函数中,增加一个public: makeEmpty()和private:makeEmpty(BinaryNode<T>* &m_Root)的函数...

为什么是两个呢,我们设置m_Root是private的,那么在public:makeEmpty()就无法使用m_Root这个变量,只能在private函数中,

增加一个重载的makeEmpty(BinaryNode<T>* &m_Root),然后在makeEmpty()中调用makeEmpty(BinaryNode<T>* &m_Root)...

这机制有点意思:保护了数据~

public:

virtual ~CBinarySearchTree()
{
    //内存怎么处理呢??
    makeEmpty();
}

void makeEmpty()

{

    makeEmpty(m_Root);

}

private:

void makeEmpty(BinaryNode<T>* &m_Root)
{
    if (m_Root)
    {
        makeEmpty(m_Root->left);
        makeEmpty(m_Root->right);
        delete t;
    }
    m_Root = NULL;
}



【C++ 代码】

#ifndef CBINARYSEARCHTREE_H
#define CBINARYSEARCHTREE_H
#include <iostream>

#define ORDER_MODE_PREV  0
#define ORDER_MODE_MID   1
#define ORDER_MODE_POST  2

//结点node
template <class T>
struct BinaryNode
{
    T                element;
    BinaryNode        *left;
    BinaryNode        *right;
    BinaryNode        *parent;
    BinaryNode(const T& _element,
               BinaryNode *_left,
               BinaryNode *_right,
               BinaryNode *_parent):
        element(_element),
        left(_left),
        right(_right),
        parent(_parent)
    {
    }
};


template <class T>
class CBinarySearchTree
{
public:

    CBinarySearchTree()
    {
        m_Root = NULL;
    }

virtual ~CBinarySearchTree()
{
    //内存怎么处理呢??
    makeEmpty();
}

    void makeEmpty()
    {
         makeEmpty(m_Root);
    }

    void insert(const T& z)
    {
        //初始化新结点,内存处理...
        BinaryNode<T>* newNode = new BinaryNode<T>(z,NULL,NULL,NULL);

        //x指向准备插入结点,y指向插入结点的父亲
        BinaryNode<T>* y = NULL;
        BinaryNode<T>* x = m_Root;

        while(x != NULL)
        {
            y = x;
            if(z < x->element)
                x = x->left;
            else
                x = x->right;
        }
        newNode->parent = y;

        //边界条件:树为空
        if(y != NULL)
        {
            if(z < y->element)
                y->left = newNode;
            else
                y->right = newNode;
        }
        else
            m_Root = newNode;
    }

    void remove(const T& z)
    {
        remove(z, m_Root);
    }

    //if return NULL :returning reference to temporary...
    //how to do it?
    const T& findMinNum() const
    {
        BinaryNode<T>* res = findMinNum(m_Root);
        return res == NULL?NULL:res->element;
    }

    const T& findMaxNum() const
    {
        BinaryNode<T>* res = findMaxNum(m_Root);
        return res == NULL?NULL:res->element;
    }


    const T& successor(T &x) const
    {
        BinaryNode<T>* res = successor(x,m_Root);
        return res == NULL?NULL:res->element;
    }


    const T& predecessor(T &x) const
    {
        BinaryNode<T>* res = predecessor(x,m_Root);
        return res == NULL?NULL:res->element;
    }




    //选择输出顺序,这个真心强大,学习了!
    void printTree(int eOrderMode = ORDER_MODE_MID)
    {
        if (ORDER_MODE_PREV == eOrderMode)
            printTreeInPrev(m_Root);
        else if (ORDER_MODE_MID == eOrderMode)
            printTreeInMid(m_Root);
        else if (ORDER_MODE_POST == eOrderMode)
            printTreeInPost(m_Root);
        else
            ;
    }

    const T& search(T &x) const
    {
        const BinaryNode<T>* res = search(x,m_Root);
        return res == NULL?NULL:res->element;
    }

private:
    void makeEmpty(BinaryNode<T>* &t)
    {
        if (t)
        {
            makeEmpty(t->left);
            makeEmpty(t->right);
            delete t;
        }
        t = NULL;
    }

    const BinaryNode<T>* search(const T value,const BinaryNode<T>* x) const
    {
        if(x == NULL || value == x->element)
            return x;
        if(value < x->element  )
            return search(value,x->left);
        else
            return search(value,x->right);
    }

    void printTreeInPrev(BinaryNode<T>* x) const
    {
        if(x == NULL)
            return;

        std::cout<<x->element<<" ";
        printTreeInPrev(x->left);
        printTreeInPrev(x->right);
    }

    void printTreeInMid(BinaryNode<T>* x) const
    {
        if(x == NULL)
            return;

        printTreeInMid(x->left);
        std::cout<<x->element<<" ";
        printTreeInMid(x->right);
    }

    void printTreeInPost(BinaryNode<T>* x) const
    {
        if(x == NULL)
            return;

        printTreeInPost(x->left);
        printTreeInPost(x->right);
        std::cout<<x->element<<" ";
    }

    void remove(const T& value, BinaryNode<T>* z)
    {
        if(z == NULL)
            return;
        if(value < z->element)
            remove(value,z->left);
        else if(value > z->element)
            remove(value,z->right);
        else if(value == z->element)
        {
            //根据z的孩子数目,我们要删除的结点y,不一样
            //当没孩子或者只有一个孩子,y就是z本身
            //两个孩子,y就是z的后继
            BinaryNode<T>* y = NULL;
            if(z->left != NULL && z->right != NULL)
                y = successor(z->element,z);
            else
                y = z;

            //x为孩子结点,从左孩子起,没有就为右孩子,再没有就NULL
            BinaryNode<T>* x = NULL;
            if(y->left != NULL)
                x = y->left;
            else
                x = y->right;

            //删除y结点就是把y孩子(x结点)接到y->parent上
            if(x != NULL)
                x->parent = y->parent;
            //边界条件:y为root结点,那么y->parent就是NULL啦。
            if(y->parent != NULL)
            {
                if(y == y->parent->left)
                {
                    y->parent->left = x;
                }
                else if(y == y->parent->right)
                {
                    y->parent->right = x;
                }
            }
            else
            {
                m_Root = x;
            }


            if(y != z)
            {
                z->element = y->element;
            }

            //算法导论就没内存概念吗?
            delete y;
        }
        else
            ;
    }

    BinaryNode<T>* findMinNum( BinaryNode<T>* x) const
    {
        while(x->left != NULL)
            x = x->left;
        return x;
    }

    BinaryNode<T>* findMaxNum( BinaryNode<T>* x) const
    {
        while(x->right != NULL)
            x = x->right;
        return x;
    }

    BinaryNode<T>* successor(const T value,const BinaryNode<T>* x) const
    {
        if(x == NULL)
            return NULL;

        if(value < x->element)
            successor(value,x->left);
        else if(value > x->element)
            successor(value,x->right);
        else
        {
            //如果有右孩子,直接返回大于自己的最小的元素
            if(x->right != NULL)
                return findMinNum(x->right);

            //找到"父结点为祖父结点的左孩子"的那个祖父结点
            BinaryNode<T>* y = NULL;
            y = x->parent;
            while(y != NULL && x == y->right)//找到x为y左孩子为止
            {
                x = y;
                y = y->parent;
            }
            return y;
        }
        return NULL;
    }

    BinaryNode<T>* predecessor(const T value, const BinaryNode<T>* x)const
    {
        if(x == NULL)
            return NULL;

        if(value < x->element)
            predecessor(value,x->left);
        else if(value > x->element)
            predecessor(value,x->right);
        else
        {

            //如果有左孩子,直接返回小于自己的最大的元素
            if(x->left != NULL)
                return findMaxNum(x->left);

            //找到"父结点为祖父结点的右孩子"的那个祖父结点
            BinaryNode<T>* y = NULL;
            y = x->parent;
            while(y != NULL && x == y->left)//找到x为y左孩子为止
            {
                x = y;
                y = y->parent;
            }
            return y;
        }

        return NULL;
    }


protected:

private:
    BinaryNode<T>* m_Root;

};

#endif // CBINARYSEARCHTREE_H



【C++测试代码】

#include <iostream>
#include "CBinarySearchTree.h"
#include "stdlib.h"

using namespace std;

int main()
{
    CBinarySearchTree<int> bst;

    //test for insert
    bst.insert(1);
    bst.insert(2);
    bst.insert(3);
    bst.insert(4);
    bst.insert(5);

    //test for printTree 有三种模式,分别为0,1,2
    cout<<"prev order: ";
    bst.printTree(ORDER_MODE_PREV);
    cout<<endl;

    cout<<"min order: ";
    bst.printTree(ORDER_MODE_MID);
    cout<<endl;

    cout<<"post order: ";
    bst.printTree(ORDER_MODE_POST);
    cout<<endl;

    //test for findMaxNum()
    cout<<"Max number: "<<bst.findMaxNum()<<endl;

    //test for findMinNum()
    cout<<"Min number: "<<bst.findMinNum()<<endl;

    //teft for successor()
    for(int i = 1 ; i <= 5 ;i++)
        cout<<"node "<<i<<" successor: "<<bst.successor(i)<<endl;

    //test for predecessor()
    for(int i = 1 ; i <= 5 ;i++)
        cout<<"node "<<i<<" predecessor: "<<bst.predecessor(i)<<endl;

    //test for search()
    for(int i = 1 ; i <= 5 ;i++)
        cout<<"node "<<i<<" search: "<<bst.search(i)<<endl;

    //test for remove()
    for(int i = 0 ; i < 5 ;i++)
    {
        bst.remove(i+1);
        cout<<"after delete "<<i+1<<": ";
        bst.printTree(ORDER_MODE_MID);
        cout<<endl;
    }

    return 0;
}

【C++ 测试结果】

prev order: 1 2 3 4 5
min order: 1 2 3 4 5
post order: 5 4 3 2 1 
Max number: 5
Min number: 1
node 1 successor: 2
node 2 successor: 0
node 3 successor: 0
node 4 successor: 0
node 5 successor: 0
node 1 predecessor: 0
node 2 predecessor: 0
node 3 predecessor: 0
node 4 predecessor: 0
node 5 predecessor: 0
node 1 search: 1
node 2 search: 2
node 3 search: 3
node 4 search: 4
node 5 search: 5
after delete 1: 2 3 4 5
after delete 2: 3 4 5
after delete 3: 4 5
after delete 4: 5
after delete 5:

Process returned 0 (0x0)   execution time : 0.546 s
Press any key to continue.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值