模仿STL,实现二叉搜索数,带迭代器 BinSearchTree (iterator)

自己看着书,实现的,废话不多说,上代码

转载请注明出处http://blog.csdn.net/u010632868

#include <iostream>
#include <assert.h>
#include <time.h>
#include <stdlib.h>
using namespace std;

template <class Type>
class BinSearchTreee;

//下面是对于树节点的声明和定义
template <class Type>
class Tree_Node
{
private:
    bool IsHeader; //判断是否是根节点,一棵树只有一个根节点
    Type Date;      //显然这是数据部分,当然根节点的数据部分,未作要求
    Tree_Node* Parent; //没一个节点都一个父节点。这里的数据结构的一大特点是,根节点的父亲节点是头节点,而头节点的父亲节点是根节点
    Tree_Node* Left;   //左儿子,对于根节点来说,Left指向元素最小的那个节点
    Tree_Node* Right;  //右儿子,对于根节点来说,Right指向元素最大的那个节点
public:
    Tree_Node(bool isheader = false,Type date = *(new Type),Tree_Node* parent = NULL,
                          Tree_Node *left = NULL,Tree_Node* right = NULL) :
                              IsHeader(isheader),Date(date),Parent(parent),
                                                Left(left),Right(right) {}

    Tree_Node(const Tree_Node &tmp) : IsHeader(tmp.IsHeader),Date(tmp.Date),
                       Parent(tmp.Parent),Left(tmp.Left),Right(tmp.Right) {}

    template <class T>
    friend class BinSearchTree; //把数结构定义为友元类
    ~Tree_Node()
    {
        cout<<“Destroy Node”<<endl;
    }

};

template <class Type>
class BinSearchTree
{
private:
    typedef Tree_Node<Type> Node; //把类型的别名写在里面。我在想如果写在外面,感觉根本没法写啊。
    typedef Tree_Node<Type>* Link;//有人知道怎么给template 的量typedef吗,知道的请告诉我,我们一起交流交流

public:
    class Iterator                 //在BinSearchTree类中嵌套定义类Iterator,主要是为更好的模仿STL的风格
    {
        Link link;                  //里面就一个Link类型,作用就不用我多说了
    public:
        Iterator(Link p = NULL) : link(p) {} //类的定义和初始化
        Iterator(const Iterator &p);
        Iterator& operator=(const Iterator &itr);
        bool operator==(const Iterator &itr);
        bool operator!=(const Iterator &itr);
        Type& operator*();
        Iterator& operator++();
        Iterator& operator–();             //后置的我省略了,反正都一样
        friend class BinSearchTree;
    };

private:
    Link Header;                            //指向根节点的指针,看名字很显然
    size_t Size;                            //记录容器内有多少元素
private:
    Iterator Find(const Type &item);        //查询
    void Prune(Link &link);                 //当link指向的节点至少有一个空节点时,调用介个家伙。
    void DeleteLink(Link &link);            //删除link指向的节点
    void Destroy(Link &link);               //自顶向下数据呈现扩张的状态,所以这里选择用自顶向下的递归调用销毁树节点
public:
    BinSearchTree();
    Iterator Insert(const Type &item);      //插入Date为item的新元素
    void Erase(Iterator itr);               //按位置删除元素
    size_t Length() {return Size;}          //返回容器大小
    Iterator Begin(){return Iterator(Header->Left);} //指向第一个元素
    Iterator End(){return Iterator(Header);} //将根节点作为end();
    ~BinSearchTree();                        //析构函数
};

template <class Type>
BinSearchTree<Type>::Iterator::Iterator(const Iterator &itr)
{
    link = itr.link;
}

template <class Type>
class BinSearchTree<Type>::Iterator& BinSearchTree<Type>::Iterator::operator=(const Iterator &itr)
{
    link = itr.link;
    return *this;
}

template <class Type>
bool BinSearchTree<Type>::Iterator::operator==(const Iterator &itr)
{
    return link == itr.link;
}

template <class Type>
bool BinSearchTree<Type>::Iterator::operator!=(const Iterator &itr)
{
    return link != itr.link;
}

template <class Type>
Type&  BinSearchTree<Type>::Iterator::operator*()
{
    return link->Date;
}

template <class Type>
class BinSearchTree<Type>::Iterator& BinSearchTree<Type>::Iterator::operator++()
{
    //第一先判断是否有右子数,不行就从父亲节点开始找。
    if(link->Right != NULL)
    {
        Link child = link->Right;
        while(child->Left != NULL)
        {
            child = child->Left;
        }
        link = child;
    }
    else //找父亲节点的关键是,当前节点为左节点
    {
        if(link->Parent->Left == link)
        {
            link = link->Parent;
        }
        else
        {
            Link parent = link->Parent;
            if(parent->Parent->Parent == parent) //一个很蛋疼的特例,当当前节点刚刚好是头节点的时候,必须额外判断。
            {
                link = parent;
            }
            else
            {

                while(parent->Parent->Right == parent)
                {
                    parent = parent->Parent;
                }
                link = parent->Parent;
            }
        }
    }
    return *this;
};

//–的思路同++,唯一的不同在最后面
template <class Type>
class BinSearchTree<Type>::Iterator& BinSearchTree<Type>::Iterator::operator–()
{
    if(link->Left != NULL)
    {
        Link child = link->Left;
        while(child->Right != NULL)
        {
            child = child->Right;
        }
        link = child;
    }
    else
    {
        if(link->Parent->Right == link)
        {
            link = link->Parent;
        }
        else
        {
            Link parent = link->Parent;
            if(parent->Parent->Parent == parent)
            {
                link = parent;
            }
            else
            {
                while(parent->Parent->Left == parent)
                {
                    parent = parent->Parent;
                }
                link = parent->Parent;
            }
        }
    }

    //为了实现逆序迭代器的功能原型,让–begin的结果为Right;
    //不过这里我并没有做相关的函数,这里只是为了以后的补充做一个方便。
    if(link->IsHeader)
    {
        link = link->Right;
    }

    return *this;
};

template <class Type>
BinSearchTree<Type>::BinSearchTree()
{
    Header = new Node;
    Header->IsHeader = true;  //只有根节点的是true,其他的都是false;
    Header->Parent = NULL;
    Header->Left = Header;
    Header->Right = Header;
    Size = 0;
}

template <class Type>
void BinSearchTree<Type>::Destroy(Link &link)
{
    if(link == NULL)
    {
        return ;
    }
    else
    {
        Destroy(link->Right);
        Destroy(link->Left);
        delete link;
    }
}

template <class Type>
class BinSearchTree<Type>::Iterator BinSearchTree<Type>::Find(const Type &item)
{
    Link parent = Header;
    Link child = parent->Parent;
    //之所以不用==符号,是为了加速。之所以为什么会更快,分析如下
    //在同为能找到的时候,该操作的时间期望都是log(n),当如果没有找到
    //那么用==判断的话,因为要先判断是否相等,如果不想等,判断在哪边,
    //这样的话,如果没有找到,该操作的期望时间就变为2*log(n);但是
    //一下这种方法,依旧是log(n);
    while(child != NULL)
    {
        if(!(child->Date > item))
        {
            child = child->Left;
        }
        else
        {
            parent = child;
            child = child->Right;
        }
    }

    if(parent == Header || parent->Date > item)
    {
        return End();
    }
    else
    {
        return parent;
    }
}

template <class Type>
class BinSearchTree<Type>::Iterator BinSearchTree<Type>::Insert(const Type &item)
{
    ++Size;
    Link parent = Header;
    Link child = Header->Parent;
    if(child == NULL)           //当树为空的时候。
    {
        Link tmp = new Node(false,item,Header,NULL,NULL);
        Header->Parent = tmp;
        Header->Left = tmp;
        Header->Right = tmp;
        return tmp;
    }
    else
    {
        while(child)
        {
            parent = child;
            if(!(item > child->Date))
            {
                child = child->Left;
            }
            else
            {
                child = child->Right;
            }
        }

        if(!(item > parent->Date))
        {
            parent->Left = new Node(false,item,parent,NULL,NULL);
            if(Header->Left == parent) { Header->Left = parent->Left;}
            return parent->Left;
        }
        else
        {
            parent->Right = new Node(false,item,parent,NULL,NULL);
            if(Header->Right == parent) { Header->Right = parent->Right;}
            return parent->Right;
        }
    }
}

template <class Type>
void BinSearchTree<Type>::Erase(Iterator itr)
{
    //删除操作,分三种情况,一种是,所要删除的节点是头节点。
    //除此之外,所要删除的节点没有子节点和有字节点的情况
    assert(!(itr.link->IsHeader));
    if(itr.link->Parent->Parent == itr.link)
    {
        DeleteLink(itr.link->Parent->Parent);
    }
    else if(itr.link->Parent->Right == itr.link)
    {
        DeleteLink(itr.link->Parent->Right);
    }
    else
    {
        DeleteLink(itr.link->Parent->Left);
    }
}

template <class Type>
void BinSearchTree<Type>::DeleteLink(Link &link)
{//注意这里是引用,这是为什么函数Erase中,要从父亲节点那里调用指向自身节点的原因。为了直接修改父亲节点的指针
    if(link->Right != NULL && link->Left != NULL)
    {
        Link child = link->Left;
        while(child->Right != NULL)
        {
            child = child->Right;
        }

        link->Date = child->Date;
        if(child == link->Left)
        {
            Prune(link->Left);
        }
        else
        {
            Prune(child->Parent->Right);
        }

    }
    else
    {
        Prune(link);
    }
}

template <class Type>
void BinSearchTree<Type>::Prune(Link &link)//这货专门用来删除至少一个子节点为空的情况
{
    –Size;
    Link tmp = link;
    if(link->Right == NULL && link->Left == NULL)//两个都为空直接删除就好了
    {
        link = NULL;
        delete tmp;
    }
    else if(link->Right != NULL)
    {
        link->Right->Parent = link->Parent;//因为是引用所以这里直接修改了父亲指针
        link = link->Right;
        if(Header->Left == tmp) //因为删除的是左边的节点,左边的节点可能是Left,所以需要做必要的判断和更新。
        {
            Link left = link;
            while(left->Left != NULL) { left = left->Left; }
            Header->Left = left;
        }
        delete tmp;
    }
    else
    {
        link->Left->Parent = link->Parent;
        link = link->Left;
        if(Header->Right == tmp) //同样因为是右边的节点,所以可以是原来的Right,所以做判断更新
        {
            Link right = link;
            while(right->Right != NULL) { right = right->Right; }
            Header->Right = right;
        }
        delete tmp;
    }
}

template <class Type>
BinSearchTree<Type>::~BinSearchTree()
{
    Destroy(Header->Parent);//递归的方式释放空间。
    delete Header;
}

int main()
{
    BinSearchTree<int> Coll;
    int i,k;
    for(i = 0;i < 10;++i)
    {
        k = rand()%100;
        Coll.Insert(k);
    }
    class BinSearchTree<int>::Iterator pos;
    for(pos = Coll.Begin();pos != Coll.End();++pos)
    {
        cout<<*pos<<‘ ‘;
    }
    cout<<“Size is : “<<Coll.Length()<<endl;
    pos = Coll.Insert(5);
    cout<<*pos<<endl;
    for(pos = Coll.Begin();pos != Coll.End();++pos)
    {
        cout<<*pos<<‘ ‘;
    }
    cout<<“Size is : “<<Coll.Length()<<endl;
    pos = Coll.Begin();
    ++pos;
    ++pos;
    Coll.Erase(pos);
    for(pos = Coll.Begin();pos != Coll.End();++pos)
    {
        cout<<*pos<<‘ ‘;
    }
    cout<<“Size is : “<<Coll.Length()<<endl;
    return 0;
}

点赞