C++ STL list模拟

在C++中,我们经常使用STL,那个在那些我们常用的数据结构vector,list的背后,又是如何实现的呢?特别是当我们使用iterator对容器进行遍历的时候,我们也能够想整数一样进行 ++ 运算。下面通过一个例子来建立一个slist,使得它能够通过iterator进行访问。

我们要实现的功能是:建立一个list存储任意个数,然后输入一个数,通过find函数查找是否在list中存在。所以我们首先要编写一个find函数,find函数的要求是能够操作多种容器,能够查找多种数据类型(int,double),所以应该建立一个模版函数。

(实际在STL中,这类函数应该叫算法,它通过iterator对容器进行遍历和操作)

所以,这个find函数应该是这样的:

template<class IteratorType,class T> 
IteratorType find(IteratorType begin,IteratorType end,const T & Value)
{
    while (begin != end && *begin != Value)
    {

        ++begin;
    }
    return begin;
}

在find函数中,我们使用模版,查找的关键字的不同类型由T处理,T可以取double,int等。另外,find的前两个参数传入的就是iterator类型的参数,它的作用就像

一个指针,分别指向容器中两个元素。查找的过程就是在这两个元素之间进行查找。从该函数还看出,begin并不是整数类型的,但是也能够通过++操作符实现遍历。

所以iterator需要重载++操作符。

   假设我们要建的list叫slist,可定义如下类:

#ifndef SIMPLELIST_H
#define SIMPLELIST_H
#include <cassert>
namespace br_stl{
/**    @brief    The slist class.<br/>
*           Description:Descripe the template list container
*/
template<class T>
class slist
{
    public:
        typedef T value_type;
        typedef ptrdiff_t difference_type;
        typedef T* pointer;
        typedef T& reference;

        /**    @brief    The constructor of slist function
             Copy constructor ,destructor and assignment operator are 
             omitted.
            @return    no return            
        */
        slist():firstElement(0),Count(0){}
        /**    \brief    The push_front function. Creates a new list element and 
                    inserts it at the beginning of the list.
            \param    Datum    a parameter of type const T&

            \return    void    
        */
        void push_front(const T& Datum);

    private:
        struct ListElement 
        {
            T Data;
            ListElement* Next;
            //constructor of the struct
            ListElement(const T& Datum,ListElement* p):Data(Datum),Next(p){}
        };
        ListElement* firstElement;
        size_t Count;
    public:
        class iterator
        {
        public:
            typedef std::forward_iterator_tag iterator_category;
            typedef T value_type;
            typedef T* pointer;
            typedef T& reference;
            typedef size_t size_type;
            typedef ptrdiff_t difference_type;
            
            iterator(ListElement* Init=0):current(Init){}
            //dereference
            T& operator*()
            {
                return current->Data;
            }
            //dereference
            const T& operator*() const
            {
                return current->Data;
            }
            //prefix ++
            iterator& operator++()
            {
                if (current){
                    current = current->Next;
                }
                return *this;
            }
            //postfix
            iterator operator++(int)
            {
                iterator temp = *this;
                ++*this;
                return temp;
            }
            
            bool operator==(const iterator& x) const
            {
                return current == x.current;
            }
            bool operator!=(const iterator& x) const
            {
                return current != x.current;
            }

        private:
            ListElement *current;//pointer to the current element.
        };//iterator

        /**    \brief    The begin function.<br/>
                     Usage:<br/>
                     container.begin()
            \return    iterator that point to the first of the container.
        */
        iterator begin() const{
            return iterator(firstElement);
        }
        /**    \brief    The end function.
            \return    iterator that point to the next one of the last element of the container(NULL).
        */
        iterator end() const{
           return iterator();
        }
};//slist
template<class T> void slist<T>::push_front(const T& Datum)
{
   firstElement = new ListElement(Datum,firstElement);
   Count++;
}
}//namespace br_stl

template<class Iterator>
int operator-(Iterator second,Iterator first)
{
    int count = 0;
    while (first != second && first != Iterator())
    {
        ++first;
        ++count;
    }
    assert(first == second);
    return count;
}

#endif

这个类我们重点关注如下几点:

1、在内部定义了一个私有的结构体:

struct ListElement 
        {
            T Data;
            ListElement* Next;
            //constructor of the struct
            ListElement(const T& Datum,ListElement* p):Data(Datum),Next(p){}
        };

结构体其实就是我们常见的单链表节点,然后结构体还定义了一个方法(C++允许结构体有方法),相当于构造函数。这个构造函数很有意思,即我们在新建一个节点的时候,节点就通过构造函数自动插入到链表了,无需在经过繁琐的指针操作。

例如 firstElement = new ListElement(23,firstElement)  将firstElement赋值给了一个新节点的Next,相当于链表的头插法。

2、除了结构体外,还定义了一个内部class,叫iterator,slist正是通过这个叫iterator的类对其本身进行遍历。

    iterator类要实现的就是几个操作符的重载,通过++符号实现p = p-> next的链表遍历操作。

现在写一段测试代码,

#include <iostream>
#include "SimpleList.h"
using namespace std;
//we do not need to modify the value here
typedef const double* IteratorType1;
//IteratorType find(IteratorType begin,IteratorType end,const int & Value);

template<class IteratorType,class T> 
IteratorType find(IteratorType begin,IteratorType end,const T & Value)
{
    while (begin != end && *begin != Value)
    {

        ++begin;
    }
    return begin;
}


int main()
{
    const int count = 100;
//    double aContainer[count];
    br_stl::slist<int> aContainer;
   // IteratorType1 begin = aContainer;
    //IteratorType1 end = aContainer+count;
    for (int i=count-1;i>=0;i--)
    {
        aContainer.push_front(i*2);
    }
    int Number = 0;
    while (Number != -1)
    {
        cout<<"Please Input a Number(-1 = end):";
        cin>>Number;
        if (Number != -1)
        {
            br_stl::slist<int>::iterator pos = find(aContainer.begin(),aContainer.end(),Number);
            if (pos != aContainer.end())
            {
                cout<<"Find at "<<pos-aContainer.begin()<<endl;
            }
            else
            {
                cout<<"not found!"<<endl;
            }
        }
    }
    return 0;
}

运行结果就是输入一个数,程序给出是否能在列表中找到。

posted @ 2013-01-17 22:03  理想空间  阅读(2125)  评论(0编辑  收藏  举报