【c++】迭代器、string类、vector类、list类的模拟实现

我们在学习完模板的基本定义之后,我们就要开始用模板来解决各种问题了。我们说模板是泛型编程,那么他就可以简化我们很多的代码量,本质上就是我们的工作交给了编译器实现。接下来我们就来模拟实现一下常用模板类。

当然模拟实现之前,我们还要补充一下迭代器的定义与功能。

C++中的迭代器是一种用于遍历容器中元素的对象。它类似于指针,可以指向容器中的元素,并且可以进行自增、自减等操作。在学习初期,我们可以简单的把迭代器认为是指针。在深入学习了之后,迭代器其实是封装屏蔽底层差异和实现细节,提供统一的访问修改遍历的一种方式,待会在我们进行模拟实现的时候,我们就可以体会的到。

一.string类

string类主要针对的是字符串,他是一个储存字符串的模板类,我们可以看看他内部的功能。

这里string的使用方式我就不多说了,重点是如何模拟实现这些功能。我挑了几个重点的功能进行模拟实现。

  class string

    {

        friend ostream& operator<<(ostream& _cout, const castle::string& s);

        friend istream& operator>>(istream& _cin, castle::string& s);

    public:

        typedef char* iterator;

    public:
        void swap(char* str)
        {
            char* tmp = str;
            str = _str;
            _str = tmp;
        }

        string(const char* str = "")
        {
            (* this).reserve(strlen(str)+1);
            int i = 0;
            while (str[i] != '\0')
            {
                _str[i] = str[i];
                i++;
            }
            _str[i] = '\0';
            _size = i;
        }

        string(const string& s)
            :_size(0),
            _capacity(0),
            _str (nullptr)
        {
            (*this).reserve(strlen(s._str) + 1);
            int i = 0;
            while (s._str[i] != '\0')
            {
                _str[i] = s._str[i];
                i++;
            }
            _str[i] = '\0';
            _size = i;
        }

        string& operator=(const string& s)
        {
            char* tmp = new char[strlen(s._str) + 1];
            strcpy(tmp, s._str);
            (*this).swap(tmp);

            _size = s._size;
            _capacity = s._capacity;

            return *this;
        }

        ~string()
        {
            delete[] _str;
            _capacity = 0;
            _size = 0;
        }



            //

            // iterator

        iterator begin()
        {
            return _str;
        }

        iterator end()
        {
            return &_str[_size];
        }



            /

            // modify

        void push_back(char c)
        {
            if (_size < _capacity)
            {
                _str[_size] = c;
            }

            else
            {
                (*this).reserve(1);
                _str[_size] = c;
            }
            _size++;
            _str[_size] = '\0';
        }

        string& operator+=(char c)
        {
            if (_size < _capacity-1)
            {
                _str[_size] = c;
            }

            else
            {
                (*this).reserve(1);
                _str[_size] = c;
            }

            _size++;
            _str[_size] = '\0';

            return *this;
        }

        void append(const char* str)
        {
            const char* tmp = str;
            while (*tmp != '\0')
            {
                *this += *tmp;
                tmp++;
            }
        }

        string& operator+=(const char* str)
        {
            const char* tmp = str;
            while (*tmp != '\0')
            {
                *this += *tmp;
                tmp++;
            }

            return *this;
        }

        void clear()
        {
            _size = 0;
        }

        void swap(string& s)
        {
            char* tmp = s._str;
            s._str = _str;
            _str = tmp;

            std::swap(_size, s._size);
            std::swap(_capacity, s._capacity);
        }

        const char* c_str()const
        {
            return _str;
        }



        /

        // capacity

        size_t size()const
        {
            int i = 0;
            while (_str[i] != '\0')
            {
                i++;
            }
            return i;
        }

        size_t capacity()const
        {
            return _capacity;
        }

        bool empty()const
        {
            if (_size == 0)
                return true;

            else
                return false;
        }

        void resize(size_t n, char c = '\0')
        {
            int size = _size;
            if (n > _size)
            {
                if (n > _capacity)
                    reserve(n-size);

                int i = size;
                while (i < n)
                {
                    _str[i] = c;
                    ++i;
                }
                _size=n;
                _str[_size] = '\0';
            }

            else
            {
                _size = n;
                _str[_size] = '\0';
            }
        }

        void reserve(size_t n)
        {
            if (_size == 0 && _capacity == 0)
            {
                char *tmp = new char[11];
                _capacity = 11;
                _str = tmp;
            }

            if (_size + n>=_capacity)
            {
                char* tmp = new char[2 * _capacity];
                _capacity *= 2;
                for (size_t i = 0; i < _size; i++)
                    tmp[i] = _str[i];
                delete[] _str;
                _str = tmp;
            }
        }



        /

        // access

        char& operator[](size_t index)
        {
            return _str[index];
        }

        const char& operator[](size_t index)const
        {
            return _str[index];
        }



        /

        //relational operators

        bool operator<(const string& s)
        {
            if (strcmp(_str, s._str) == -1)
                return true;

            else
                return false;
        }

        bool operator<=(const string& s)
        {
            if (*this < s || *this == s)
                return true;

            else
                return false;
        }

        bool operator>(const string& s)
        {
            if (*this <= s)
                return false;

            else
                return true;
        }

        bool operator>=(const string& s)
        {
            if (*this < s)
                return false;

            else
                return true;
        }

        bool operator==(const string& s)
        {
            if (strcmp(_str, s._str) == 0)
                return true;

            else
                return false;
        }


        bool operator!=(const string& s)
        {
            if (*this == s)
                return false;

            else
                return true;
        }



        // 返回c在string中第一次出现的位置

        size_t find(char c, size_t pos = 0) const
        {
      
            while (_str[pos] != c)
            {
                if (pos == _size)
                    break;
                pos++;
            }
            
            if (pos == _size)
                return 0;

            else return pos;
        }

        // 返回子串s在string中第一次出现的位置

        size_t find(const char* s, size_t pos = 0) const
        {
            char* tmp = strstr(&_str[pos], s);
            if (tmp == nullptr)
                return 0;

            char* begin = _str;
            int count = 0;
            while (begin != tmp)
            {
                begin++;
                count++;
            }

            return count;
        }

        // 在pos位置上插入字符c/字符串str,并返回该字符的位置

        string& insert(size_t pos, char c)
        {
            *this += '\0';
            size_t cur = _size-1;
            while (cur != pos)
            {
                _str[cur + 1] = _str[cur];
                cur--;
            }

            if (pos == _size-1)
            {
                _str[_size] = _str[_size-1];
                _str[pos] = c;
            }

            else
                _str[pos+1] = c;

            return *this;
        }

        string& insert(size_t pos, const char* str)
        {
            size_t size = strlen(str);
            for (int i = 0; i < size; ++i)
                *this += '\0';

            size_t cur = _size;
            while (cur != pos)
            {
                _str[cur + 3] = _str[cur];
                cur--;
            }

            for (int i = 0; i < size; ++i)
            {
                _str[pos+1] = str[i];
                ++pos;
            }

            return *this;
        }



        // 删除pos位置上的元素,并返回该元素的下一个位置

        string& erase(size_t pos, size_t len)
        {
            size_t cur = pos + len;
            while (cur != _size)
            {
                _str[cur - len] = _str[cur];
                cur++;
            }
            _size -=len;
            _str[_size] = '\0';
            return *this;
        }

    private:

        char* _str;

        size_t _capacity=0;

        size_t _size=0;

    };
    ostream& operator<<(ostream& _cout, const castle::string& s)
    {
        int i = 0;
        while (s._str[i] != '\0')
        {
            _cout << s._str[i];
            i++;
        }

        _cout << endl;

        return _cout;
    }

    istream& operator>>(istream& _cin, castle::string& s)
    {
        char ch;
        ch = getchar();
        while (ch != '\n')
        {
            s += ch;
            ch = getchar();
        }

        return _cin;
    }

string里面的内容我挑了这一些来实现,我们主要要确定其内置类型,才能进行对这个类的功能进行实现,其余的无非就是对数据结构的选择,内部的操作也不是非常的难,大家可以看一下。

二.vector类

在vector中,我们对于模板的应用据更广泛了,我们来看:

    template<class T>

    class vector
    {

    public:

            // Vector的迭代器是一个原生指针

            typedef T* iterator;

            typedef const T* const_iterator;

            iterator begin()
            {
                return _start;
            }

            iterator end()
            {
                return _finish;
            }

            const_iterator begin() const
            {
                return _start;
            }

            const_iterator end() const
            {
                return _finish;
            }



            // construct and destroy

            vector()
                :_start(nullptr),
                _finish(nullptr),
                _endOfStorage(nullptr)
            {}

            vector(int n, const T& value = T())
                :_start(nullptr),
                _finish(nullptr),
                _endOfStorage(nullptr)
            {
                resize(n, value);
            }

            template<class InputIterator>

            vector(InputIterator first, InputIterator last)
                :_start(nullptr),
                _finish(nullptr),
                _endOfStorage(nullptr)
            {
                InputIterator it = first;
                while (it != last)
                {
                    push_back(*it);
                    ++it;
                }
            }

            vector(const vector<T>& v)
                :_start(nullptr),
                _finish(nullptr),
                _endOfStorage(nullptr)
            {
                for (auto x : v)
                    push_back(x);
            }

            vector<T>& operator= (vector<T> v)
            {
                 int cap= v._endOfStorage- v._start;

                 vector<T> tmp;
                 for (auto x : v)
                 {
                     tmp.push_back(x);
                 }
                 swap(tmp);

                 return *this;
            }

            ~vector()
            {

            }

            // capacity

            size_t size() const
            {
                return _finish - _start;
            }

            size_t capacity() const
            {
                return _endOfStorage - _start;
            }

            void reserve(size_t n)
            {
                int size = _finish - _start;
                int cap = _endOfStorage - _start;
                if (_start == nullptr)
                {
                    T* tmp = new T[10];
                    
                    _start = tmp;
                    _finish = _start + 1;
                    _endOfStorage = _start + 10;
                }

                else
                {
                    if (n >= cap)
                    {
                        T* tmp = new T[2*cap];
                        T* cur = tmp;
                        for (auto x : *this)
                        {
                            *cur = x;
                            cur++;
                        }

                        _start = tmp;
                        _finish = _start + size;
                        _endOfStorage = _start + 2*cap;

                        //swap(_start, tmp._start);
                        //swap(_finish, tmp._finish);
                        //swap(_endOfStorage, tmp._endOfStorage);
                    }
                }
                    
            }

            void resize(size_t n, const T& value = T())
            {          
                if (_start == nullptr)
                    reserve(10);

                int num = _endOfStorage - _start;
                if (n < num)
                {
                    _finish = _start + n + 1;
                    auto it = begin();
                    while (it != end())
                    {
                        *it = value;
                        it++;
                    }
                    /*for (auto x : *this)
                        x = value;*/
                }

                else
                {
                    reserve(n);
                    _finish = _start + n + 1;
                    //for (auto x : *this)
                    //    x = value;
                    auto it = begin();
                    while (it != end())
                    {
                        *it = value;
                        it++;
                    }
                }
            }



            ///access///

            T& operator[](size_t pos)
            {
                return *(_start + pos);
            }

            const T& operator[](size_t pos)const
            {
                return *(_start + pos);
            }



            ///modify/

            void push_back(const T& x)
            {
                if (_start == nullptr)
                {
                    reserve(1);
                    *_start = x;
                }

                else
                {
                    if (_endOfStorage + 1 == _finish)
                        reserve(2 * (_endOfStorage-_start));

                    *_finish = x;
                    _finish++;
                }
            }

            void pop_back()
            {
                _finish--;
            }

            void swap(vector<T>& v)
            {
                std::swap(_start, v._start);
                std::swap(_finish, v._finish);
                std::swap(_endOfStorage, v._endOfStorage);
            }

            iterator insert(iterator pos, const T& x)
            {
                if (_endOfStorage + 1 == _finish)
                    reserve(5);

                iterator cur = _finish;
                while (cur != pos)
                {
                    *cur = *(cur - 1);
                    cur--;
                }

                *pos = x;
                _finish++;

                return pos;
            }

            iterator erase(iterator pos)
            {
                iterator cur = pos;
                while (cur != _finish)
                {
                    *cur = *(cur + 1);
                    cur++;
                }

                _finish--;

                return pos;
            }

    private:

        iterator _start; // 指向数据块的开始

        iterator _finish; // 指向有效数据的尾

        iterator _endOfStorage; // 指向存储容量的尾

    };

可以看到,vector中的内置类型都变成了迭代器。其实vector的本质就是顺序表,跟string不同,他是可以对任意类型创建顺序表,实现了泛型编程,更能提现模板的重要性。

三.list类

list的本质就是带头双向循环链表,这个在数据结构中我们也实现过,我们现在在c++类中模拟实现一下,我们可以更加体会到迭代器的重要性。

namespace castle
{

    // List的节点类
    template<class T>
    struct ListNode
    {
        ListNode(const T& val = T())
            :_pPre(nullptr),
            _pNext(nullptr),
            _val(val)
        {}
        
        ListNode<T>* _pPre;
        ListNode<T>* _pNext;
        T _val;
    };


    template<class Iterator, class Ref, class Ptr>
    class Reverse_iterator
    {
        typedef Reverse_iterator<Iterator, Ref, Ptr> Self;
        Iterator _it;

    public:
        Reverse_iterator(Iterator it)
            :_it(it)
        {}

        Self& operator++()
        {
            _it--;
            return *this;
        }

        Self operator++(int)
        {
            Self tmp(*this);
            _it--;
            return tmp;
        }

        Self& operator--()
        {
            _it++;
            return *this;
        }

        Self operator--(int)
        {
            Self tmp(*this);
            _it++;
            return tmp;
        }

        Ref operator*()
        {
            Iterator tmp = _it;

            return *(--tmp);
        }

        Ptr operator->()
        {
            return &(operator*());
        }

        bool operator!=(const Self& l)
        {
            return l._it != _it;
        }

        bool operator==(const Self& l)
        {
            return l._it == _it;
        }

    };
    // vector和list反向迭代器实现


    //List的迭代器类
    template<class T, class Ref, class Ptr>
    class ListIterator
    {
    public:
        typedef ListNode<T>* PNode;
        typedef ListIterator<T, Ref, Ptr> Self;
    public:
        ListIterator(PNode pNode = nullptr)
            :_pNode(pNode)
        {}

        ListIterator(const Self& l)
        {
            _pNode = l._pNode;
        }

        Ref operator*()
        {
            return _pNode->_val;
        }

        Ptr operator->()
        {
            return &(_pNode->_val);
        }

        Self& operator++()
        {
            _pNode=_pNode->_pNext;
            return *this;
        }

        Self operator++(int)
        {
            Self tmp(*this);
            _pNode = _pNode->_pNext;
            return tmp;
        }

        Self& operator--()
        {
            _pNode = _pNode->_pPre; 
            return *this;
        }

        Self operator--(int)
        {
            Self tmp(*this);
            _pNode = _pNode->_pPre;
            return tmp;
        }

        bool operator!=(const Self& l)
        {
            return l._pNode != _pNode;
        }

        bool operator==(const Self& l)
        {
            return l._pNode == _pNode;
        }

        PNode _pNode;
    };



    //list类
    template<class T>
    class list
    {
        typedef ListNode<T> Node;
        typedef Node* PNode;
    public:
        typedef ListIterator<T, T&, T*> iterator;
        typedef ListIterator<T, const T&, const T*> const_iterator;

        typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
        typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;
    public:
        ///
        // List的构造
        list()
        {
            CreateHead();
        }

        list(int n, const T& value = T())
        {
            CreateHead();
            while (n != 0)
            {
                push_back(value);
                n--;
            }
        }

        template <class Iterator>
        list(Iterator first, Iterator last)
        {
            CreateHead();
            iterator it = first;
            while (it != last)
            {
                push_back(*it);
                it++;
            }
        }

        list(const list<T>& l)
        {
            CreateHead();
            auto it = l.begin();

            while (it != l.end())
            {
                push_back(*it);
                it++;
            }
        }

        list<T>& operator=(const list<T> l)
        {
            list<T> tmp;
            auto it = l.begin();

            while (it != l.end())
            {
                tmp.push_back(*it);
                it++;
            }

            swap(tmp);
            return *this;
        }

        ~list()
        {

        }


        ///
        // List Iterator
        iterator begin()
        {
            return iterator(_pHead->_pNext);
        }

        iterator end()
        {
            return iterator(_pHead);
        }

        const_iterator begin() const
        {
            return const_iterator(_pHead->_pNext);
        }

        const_iterator end() const
        {
            return const_iterator(_pHead);
        }

        
        reverse_iterator cbegin()
        {
            return reverse_iterator(end());
        }

        reverse_iterator cend()
        {
            return reverse_iterator(begin());
        }

        const_reverse_iterator cbegin() const
        {
            return const_reverse_iterator(end());
        }

        const_reverse_iterator cend() const
        {
            return const_reverse_iterator(begin());
        }

        ///
        // List Capacity
        size_t size()const
        {
            size_t i = 0;
            PNode cur = _pHead->_pNext;
            while (cur != _pHead)
            {
                cur=cur->_pNext;
                i++;
            }
            return i;
        }

        bool empty()const
        {
            return _pHead->_pNext == _pHead;
        }


        
        // List Access
        T& front()
        {
            return _pHead->_pNext->_val;
        }

        const T& front()const
        {
            return _pHead->_pNext->_val;
        }

        T& back()
        {
            return _pHead->_pPre->_val;
        }

        const T& back()const
        {
            return _pHead->_pPre->_val;
        }


        
        // List Modify
        void push_back(const T& val) 
        {
            insert(end(), val); 
        }

        void pop_back() 
        {
            erase(--end());
        }

        void push_front(const T& val) 
        { 
            insert(begin(), val);
        }

        void pop_front() 
        {
            erase(begin());
        }

        // 在pos位置前插入值为val的节点
        iterator insert(iterator pos, const T& val)
        {
            Node* newnode = new Node;
            newnode->_val = val;

            newnode->_pNext = pos._pNode;
            newnode->_pPre = pos._pNode->_pPre;
            newnode->_pPre->_pNext = newnode;
            pos._pNode->_pPre = newnode;

            return pos._pNode->_pPre;
        }

        // 删除pos位置的节点,返回该节点的下一个位置
        iterator erase(iterator pos)
        {
            pos._pNode->_pPre->_pNext = pos._pNode->_pNext;
            pos._pNode->_pNext->_pPre = pos._pNode->_pPre;
            PNode ret = pos._pNode->_pNext;
            delete pos._pNode;

            return ret;
        }

        void clear()
        {
            _pHead->_pNext = _pHead;
            _pHead->_pPre = _pHead;
        }

        void swap(list<T>& l)
        {
            std::swap(_pHead, l._pHead);
        }

        void CreateHead()
        {
            _pHead = new Node;
            _pHead->_pNext = _pHead;
            _pHead->_pPre = _pHead;
            _pHead->_val = 0;
        }

    private:
        PNode _pHead;
    };

在castle命名空间里,我们实现了多个类,有节点类,有迭代器类,有链表类,我们要围绕着链表类来依靠其他类来做补充,其中最难的是迭代器类,我们可以看到定义了正反向迭代器,其实原理是一样的,但是实现会比vector更加复杂一些,它涉及了返回节点指针,返回节点值和值的指针,使用大家在实现的时候要注意小细节。

这就是三个类的全部实现,大家可以看着我的代码来自己也模拟实现一下!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值