STL之list简要实现

STL 专栏收录该内容
3 篇文章 0 订阅

(1)内存模型及实现接口

 

(2) 源代码及简要注释

sort性能比较低,对100万条随机数据排序要140秒左右,原版list的sort算法仅要1.4秒

#ifndef TINY_LIST

#include <memory>

namespace tiny_stl
{
    //注意:此tiny_list有四种insert版本
    //其中
    //template <typename Input> 
    //iterator insert(const iterator& pos, const Input &first, const Input &last)
    //和
    //iterator insert(const iterator& pos, size_type count, const value_type& value)
    //可能会发生重载冲突,如果value_type = int
    template <typename T>
    struct list_node //将数据封装为结点
    {
        T *data;
        list_node *next;
        list_node *prev;
        
        list_node(const T& value): data(new T(value)), next(NULL), prev(NULL) { }
        list_node(): data(NULL), next(NULL), prev(NULL) { }
        ~list_node()
        {
            delete data;
        }
        T& operator*() const //重载*,便于取数据
        {
            return *data;
        }
    };
    template <typename T>
    class list_iterator //list专属迭代器
    {
    private:
        using value_type = T;
        using self = list_iterator;
    public:
        list_node<value_type> *node; //所指向的结点
    public:
        list_iterator(list_node<value_type> *_node): node(_node) { }
    public:
        self& operator++() //前置自增
        {
            node = node -> next;
            return *this;
        }
        self operator++(int) //后置自增
        {
            self tmp = *this;
            ++*this;
            return tmp;
        }
        self& operator--() //前置自减
        {
            node = node -> prev;
            return *this;
        }
        self operator--(int)//后置自减
        {
            self tmp = *this;
            --*this;
            return tmp;
        }
        value_type& operator*() const
        {
            return *(*node);
        }
        bool operator==(const self &it) const
        {
            return node == it.node;
        }
        bool operator!=(const self &it) const
        {
            return node != it.node;
        }
    };

    template <typename T>
    bool less_cmp(const T &a, const T &b) //默认小于比较运算符
    {
        return a < b;
    }
    template <typename T>
    bool equal_cmp(const T &a, const T &b) //默认等于比较运算符
    {
        return a == b;
    }

    template <typename T, typename U = std::allocator<T> >
    class tiny_list
    {
    public:
        using value_type = T;
        using allocator_type = U;
        using size_type = size_t;
        using node_type = list_node<value_type>;
    private:
        node_type *node; //空结点
        size_type elem_size; //记录大小
        static allocator_type alloc; //内存分配器,虽然没用
        using iterator = list_iterator<value_type>;
    private:
        template <typename Input>
        node_type* insert_aux(node_type *pos, const Input &first, const Input &last)
        //把first到last之间的所有对象插入到pos之前,使用头插法
        {
            node_type *first_insert;
            Input cur = first;
            while(cur != last)
            {
                node_type* new_node = new node_type(*cur);
                pos -> prev -> next = new_node;
                new_node -> prev = pos -> prev;
                pos -> prev = new_node;
                new_node -> next = pos;
                if(cur == first)
                {
                    first_insert = new_node; //记录第一个被插入的结点
                }
                cur++;
                elem_size++;

            }
            return first_insert;
        }
        void free_space()
        {
            if(node) //移后源对象的node可能为空,所以需要检查一下
            {
                clear();
                delete node;
                node = NULL;
            }
        }
        template <typename Compare>
        void insert_sort(node_type *first, node_type *last, Compare comp)
        //链表的插入排序,需要指定比较函数,a小于b当且仅当comp(a,b)为真
        {
            node_type *extern_cur = first -> next;
            while(extern_cur != last -> next)
            {
                value_type *tmp = extern_cur -> data;
                node_type *intern_cur = extern_cur -> prev;
                while(intern_cur != first -> prev && comp(*tmp, *(*intern_cur)))
                {
                    intern_cur -> next -> data = intern_cur -> data;
                    intern_cur = intern_cur -> prev;
                }
                intern_cur -> next -> data = tmp;
                extern_cur = extern_cur -> next;
            }
        }
        template <typename Compare>
        void quick_sort(node_type *first, node_type *last, size_type count, Compare comp)
        //非递归的快速排序
        {
            struct list_info
            {
                node_type *first;
                node_type *last;
                size_type count;
            };
            tiny_vector<list_info> info_stack; //记录待排序的链表头结点和尾结点,以及长度
            info_stack.reserve(count); //提前开辟好空间
            value_type *piviot; //每次划分时的依据
            size_type left_count; //记录划分后左半部分的长度
            do
            {
                if(!first) //从栈中取出一段待排序的链表
                {
                    list_info tmp = info_stack.back();
                    info_stack.pop_back();
                    first = tmp.first;
                    last = tmp.last;
                    count = tmp.count;
                }

                if(count <= 100) //如果待排序的链表长度比较小,则调用插入排序
                {
                    insert_sort(first, last, comp);
                    first = NULL;
                    continue;
                }

                node_type *left = first, *right = last;
                //由于随机选取链表中的某个结点是不太方便的,划分依据永远是最左端的结点or最右端的结点
                //以count的奇偶性来决定,增加一点随机性
                if(count & 1)
                {
                    piviot = left -> data;
                }
                else
                {
                    piviot = right -> data;
                    right -> data = left -> data;
                    left -> data = piviot;
                }
                
                left_count = 0;
                while(left != right) //根据piviot将链表划分为两部分
                {
                    while(right != left && !comp(**right, *piviot))
                    {
                        right = right -> prev;
                    }
                    left -> data = right -> data;
                    left_count++;
                    while(left != right && comp(**left, *piviot))
                    {
                        left = left -> next;
                        left_count++;
                    }
                    right -> data = left -> data;
                }
                left -> data = piviot;

                if(left != last && left -> next != last) 
                //划分后的右半部分链表还有1个以上的结点,则将这段链表的信息压入栈中
                {
                    info_stack.push_back({left -> next, last, count - left_count});
                }
                if(left != first && left -> prev != first)
                //划分后的左半部分链表还有1个以上的结点,则这段链表作为下一次迭代时的被排序链表
                {
                    last = left -> prev;
                    count = left_count;
                }
                else //否则,下一次迭代时从栈中弹出链表,以作为被排序链表
                {
                    first = NULL;
                }

            }while(!info_stack.empty() || first);
        }
    public: //五大拷贝控制成员
        tiny_list(): node(new node_type), elem_size(0)
        {
            node->next = node->prev = node;
        }
        tiny_list(const tiny_list &_lt): tiny_list()
        {
            insert_aux(node, _lt.begin(), _lt.end());
        }
        tiny_list& operator=(const tiny_list &_lt)
        {
            if(this != &_lt)
            {
                clear();
                insert_aux(node, _lt.begin(), _lt.end());
            }
            return *this;
        }
        tiny_list(tiny_list &&_lt): node (_lt.node), elem_size(_lt.elem_size) //移动构造,接管资源
        {
            _lt.node = NULL; //确保移后源对象销毁安全
        }
        tiny_list& operator=(tiny_list &&_lt)
        {
            if(this != &_lt)
            {
                free_space();
                node = _lt.node;
                elem_size = _lt.elem_size;
                _lt.node = NULL;
                _lt.elem_size = 0;
            }
            return *this;
        }
        ~tiny_list()
        {
            free_space();
        }
    public: //常用接口
        iterator begin() const
        {
            return iterator(node -> next);
        }
        iterator end() const
        {
            return iterator(node);
        }
        value_type& front() const
        {
            return *(*(node->next));
        }
        value_type& back() const
        {
            return *(*(node->prev));
        }
        bool empty() const
        {
            return node -> next == node;
        }
        size_type size() const
        {
            return elem_size;
        }
        void clear()
        {
            node_type *cur_node = node -> next;
            while(cur_node != node)
            {
                cur_node = cur_node -> next;
                delete cur_node -> prev;
            }
            node->next = node->prev = node;
            elem_size = 0;
        }
        void swap(tiny_list &_lt)
        {
            if(this != &_lt)
            {
                std::swap(node, _lt.node);
                std::swap(elem_size, _lt.elem_size);
            }
        }
        void resize(size_type n, const value_type &value = value_type())
        {
            if(n < elem_size)
            {
                node_type *cur = node -> prev;
                while(elem_size > n)
                {
                    cur = cur -> prev;
                    delete cur -> next;
                    elem_size--;
                }
                cur -> next = node;
                node -> prev = cur;
            }
            else if(n > elem_size)
            {
                insert(node, n - elem_size, value);
            }
        }
        iterator insert(const iterator& pos, size_type count, const value_type &value)
        {
            node_type *first_insert, *pos_node = pos.node;
            for(int i = 0; i < count; ++i)
            {
                node_type *new_node = new node_type(value);
                pos_node -> prev -> next = new_node;
                new_node -> prev = pos_node -> prev;
                pos_node -> prev = new_node;
                new_node -> next = pos_node;
                if(!i)
                {
                    first_insert = new_node;
                }
            }
            elem_size += count;
            return iterator(first_insert);
        }
        iterator insert(const iterator& pos, const value_type &value)
        {
            return insert(pos, size_type(1), value);
        }
        template <typename Input>
        iterator insert(const iterator& pos, const Input &first, const Input &last)
        {
            return iterator(insert_aux(pos.node, first, last)); 
        }
        iterator insert(const iterator &pos, std::initializer_list<value_type> &_ilist)
        {
            return iterator(insert_aux(pos.node, _ilist.begin(), _ilist.end()));
        }
        iterator erase(const iterator& first, const iterator& last)
        {
            node_type *cur = first.node, *last_node = last.node;
            node_type *tmp = cur -> prev;
            while(cur != last_node)
            {
                cur = cur -> next;
                delete cur -> prev;
                elem_size--;
            }
            tmp -> next = last_node;
            last_node -> prev = tmp;
            return last;
        }
        iterator erase(const iterator &pos)
        {
            return erase(pos, iterator(pos.node -> next));
        }
        void push_back(const value_type &value)
        {
            insert(iterator(node), size_type(1), value);
        }
        void pop_back()
        {
            if(!elem_size)
            {
                return;
            }
            erase(iterator(node -> prev), iterator(node));
        }
        void push_front(const value_type &value)
        {
            insert(iterator(node->next), size_type(1), value);
        }
        void pop_front()
        {
            if(!elem_size)
            {
                return;
            }
            erase(iterator(node -> next), iterator(node -> next -> next));
        }
        void merge(tiny_list &_lt, bool (*comp)(const value_type&, const value_type&) = less_cmp) 
        //以升序排列
        {
            if(this == &_lt) //如果是同一个对象,则不做任何动作
            {
                return;
            }
            else if(!elem_size)
            {
                swap(_lt); //如果本对象无元素,则直接交换两对象即可
            }
            node_type *p = node -> next, *q = _lt.node -> next;
            elem_size += _lt.elem_size;
            while(q != _lt.node) //思路是将_lt中的元素一个个插入到本对象中
            {
                while(p != node && comp(*(p->data), *(q->data)))  //找到正确的位置,在此位置之前插入元素
                {
                    p = p -> next;
                }
                node_type *q_next = q -> next;
                p -> prev -> next = q;
                q -> prev = p -> prev;
                q -> next = p;
                p -> prev = q;
                q = q_next;
            }
            _lt.node -> next = _lt.node -> prev = _lt.node; //对链表q进行收尾工作
        }
        void splice(const iterator &pos, tiny_list &other, iterator it)
        {
            auto tmp = it;
            splice(pos, other, it, ++tmp);
        }
        void splice(const iterator &pos, tiny_list &other)
        {
            splice(pos, other, other.begin(), other.end());
        }
        void splice(const iterator &pos, tiny_list &other, const iterator &first, const iterator &last)
        //将链表other的从first到last之间的所有对象转移到本链表的pos之前
        {
            if(first == last)
            {
                return;
            }
            node_type *first_node = first.node, *last_node = last.node, *pos_node = pos.node;

            size_type count = 0;
            node_type *cur = first_node; //统计转移的对象数量
            while(cur != last_node)
            {
                cur = cur -> next;
                count++;
            }

            last_node = last_node -> prev; //将尾后结点改成尾结点
            first_node -> prev -> next = last_node -> next;
            last_node -> next -> prev = first_node -> prev;
            other.elem_size -= count;

            pos_node -> prev -> next = first_node;
            first_node -> prev = pos_node -> prev;
            last_node -> next = pos_node;
            pos_node -> prev = last_node;
            elem_size += count;
        }
        void reverse() //翻转链表
        {
            if(!elem_size || elem_size == 1)
            {
                return;
            }
            node_type *front = node ,*middle = node -> next, *rear = middle -> next;
            do
            {
                front -> prev = middle;
                middle -> next = front;
                front = middle;
                middle = rear;
                rear = rear -> next;
            }while(front != node);
        }
        size_type unique(bool (*comp)(const value_type&, const value_type&) = equal_cmp)
        //对于连续出现的元素,将其数量缩减为1
        {
            if(!elem_size)
            {
                return 0;
            }
            node_type *first_appear = node -> next, *cur = first_appear -> next;
            size_type count = 0;
            while(first_appear != node)
            {
                if(cur != node && comp(*(*first_appear), *(*cur)))
                {
                    cur = cur -> next;
                    delete cur->prev;
                    count++;
                }
                else
                {
                    cur -> prev = first_appear;
                    first_appear -> next = cur;
                    first_appear = cur;
                    cur = cur -> next;
                }
            }          
            elem_size -= count;
            return count;
        }
        void sort(bool (*comp)(const value_type&, const value_type&) = less_cmp)
        //对链表排序
        {
            quick_sort(node -> next, node -> prev, elem_size, comp);
        }
    };
    template <typename T, typename U>
    U tiny_list<T, U>::alloc;
}

#endif

 

  • 0
    点赞
  • 1
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页

打赏

ForBestSelf

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值