zoukankan      html  css  js  c++  java
  • 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;
    }

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

  • 相关阅读:
    spring mvc DispatcherServlet详解之一---处理请求深入解析
    spring mvc DispatcherServlet详解之前传---前端控制器架构
    [推荐]趣味剖析Spring5核心原理
    源码揭秘mybatis日志实现的原理
    mybatis返回自增主键踩坑记
    根据身份证号码判定原籍地的方法
    深入源码解析spring aop实现的三个过程
    匆忙--一个大龄十年老程序员战战兢兢的应对中年危机的2019年总结与2020年展望
    Java 趟坑录
    迷你MVVM框架 avalonjs1.5 入门教程
  • 原文地址:https://www.cnblogs.com/jianboqi/p/2865017.html
Copyright © 2011-2022 走看看