卖不甜枣 发表于 2024-11-3 13:47:44

list(c++)

list介绍

list是STL容器中的容器,且元素在容器中的位置是分散的并与巨细无关。list的底层是双向链表,其优势是在恣意位置插入和删除元素的时间复杂度为O(1),但无法通过“下标[ ]”直接访问元素,需要通过从头(尾)遍历元素找到元素,多用于需要大量数据的插入和删除,且对数据的随机访问比较少。

list利用

一、list的构造

构造函数接口分析         list (size_type n, const value_type& val =       value_type())                构造的      list      中包罗      n      个值为      val      的      元素               list()               构造空的      list               list (const list& x)               拷贝构造函数               list (InputIterator first, InputIterator last)               用            区间中的元素构造      list        
// list的构造
    list<int> l1;                         // 构造空的l1
    list<int> l2(4, 100);               // l2中放4个值为100的元素
    list<int> l3(l2.begin(), l2.end());// 用l2的[begin(), end())左闭右开的区间构造l3
    list<int> l4(l3);                  // 用l3拷贝构造l4

    // 以数组为迭代器区间构造l5
    int array[] = { 16,2,77,29 };
    list<int> l5(array, array + sizeof(array) / sizeof(int));

    // 列表格式初始化C++11
    list<int> l6{ 1,2,3,4,5 }; 二、list 的iterator的利用

 
接口分析         begin       +       end                返回第一个元素的迭代器      +      返回最后一个元素下一个位置的迭代器               rbegin                 +       rend               返回第一个元素的      reverse_iterator,      即      end      位置      ,      返回最后一个元素下一个位      置的      reverse_iterator,      即      begin      位置        
// list迭代器的使用
// 注意:遍历链表只能用迭代器和范围for
void PrintList(const list<int>& l)
{
    // 注意这里调用的是list的 begin() const,返回list的const_iterator对象
    for (list<int>::const_iterator it = l.begin(); it != l.end(); ++it)
    {
      cout << *it << " ";
      // *it = 10; 编译不通过
    }

    cout << endl;
}

void TestList2()
{
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    list<int> l(array, array + sizeof(array) / sizeof(array));
    // 使用正向迭代器正向list中的元素
    // list<int>::iterator it = l.begin();   // C++98中语法
    auto it = l.begin();                     // C++11之后推荐写法
    while (it != l.end())
    {
      cout << *it << " ";
      ++it;
    }
    cout << endl;

    // 使用反向迭代器逆向打印list中的元素
    // list<int>::reverse_iterator rit = l.rbegin();
    auto rit = l.rbegin();
    while (rit != l.rend())
    {
      cout << *rit << " ";
      ++rit;
    }
    cout << endl;
}
三、list capacity

接口分析empty         检测      list      是否为空,是返回      true      ,否则返回      false      size         返回      list      中有用节点的个数        四、list element access

接口分析front         返回      list      的第一个节点中值的引用      back         返回      list      的最后一个节点中值的引用       五、list modifiers 

接口分析push_front         在      list      首元素前插入值为      val      的元素      pop_front         删除      list      中第一个元素      push_back         在      list      尾部插入值为      val      的元素      pop_back         删除      list      中最后一个元素      insert         在      list position       位置中插入值为      val      的元素      erase         删除      list position      位置的元素      swap         互换两个      list      中的元素      clear         清空      list      中的有用元素       // list插入和删除
// push_back/pop_back/push_front/pop_front
void TestList3()
{
    int array[] = { 1, 2, 3 };
    list<int> L(array, array + sizeof(array) / sizeof(array));

    // 在list的尾部插入4,头部插入0
    L.push_back(4);
    L.push_front(0);
    PrintList(L);

    // 删除list尾部节点和头部节点
    L.pop_back();
    L.pop_front();
    PrintList(L);
}

// insert /erase
void TestList4()
{
    int array1[] = { 1, 2, 3 };
    list<int> L(array1, array1 + sizeof(array1) / sizeof(array1));

    // 获取链表中第二个节点
    auto pos = ++L.begin();
    cout << *pos << endl;

    // 在pos前插入值为4的元素
    L.insert(pos, 4);
    PrintList(L);

    // 在pos前插入5个值为5的元素
    L.insert(pos, 5, 5);
    PrintList(L);

    // 在pos前插入[v.begin(), v.end)区间中的元素
    vector<int> v{ 7, 8, 9 };
    L.insert(pos, v.begin(), v.end());
    PrintList(L);

    // 删除pos位置上的元素
    L.erase(pos);
    PrintList(L);

    // 删除list中[begin, end)区间中的元素,即删除list中的所有元素
    L.erase(L.begin(), L.end());
    PrintList(L);

// 交换l1和l2中的元素
    list<int> l2;
    l1.swap(l2);
    PrintList(l1);
    PrintList(l2);

    // 将l2中的元素清空
    l2.clear();
    cout << l2.size() << endl;
}  六、list的迭代器失效

      可将迭代器临时理解成雷同于指针,迭代器失效即迭代器所指向的节点的无   效,即该节点被删除了。由于list的底层布局为带头结点的双向循环链表,因此在list中举行插入   时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭   代器,其他迭代器不会受到影响。    void TestListIterator1()
{
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    list<int> l(array, array+sizeof(array)/sizeof(array));
    auto it = l.begin();
    while (it != l.end())
      {
      // erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给
      其赋值
      l.erase(it);
      ++it;
      }
}
// 改正
void TestListIterator()
{
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    list<int> l(array, array+sizeof(array)/sizeof(array));
    auto it = l.begin();
    while (it != l.end())
    {
      l.erase(it++); // it = l.erase(it);
    }
}  
模拟实现

一、节点

template<class T>
        struct list_node
        {
                T _data;
                list_node<T>* _next;
                list_node<T>* _prev;

                list_node(const T& x = T())
                        :_data(x)
                        , _next(nullptr)
                        , _prev(nullptr)
                {}
        }; 二、构造

      void empty_init()
                {
                        _head = new Node();
                        _head->_next = _head;
                        _head->_prev = _head;
                        _size = 0;
                }
       //无参构造
                list()
                {
                        empty_init();
                }
      //拷贝构造
                // lt2(lt1)
                list(const list<T>& lt)
                {
                        empty_init();

                        for (auto& e : lt)
                        {
                                push_back(e);
                        }
                }
      //n个val构造
      list(size_t n, const T& val = T())
                {
                        empty_init();
                        for (size_t i = 0; i < n; i++)
                        {
                                push_back(val);
                        }
                } 三、迭代器

迭代器:类封装节点指针,重载运算符,模拟指针的行为
        template<class T, class Ref, class Ptr>
        struct list_iterator
        {
                typedef list_node<T> Node;
                typedef list_iterator<T, Ref, Ptr> Self;
                Node* _node;

                list_iterator(Node* node)
                        :_node(node)
                {}

                Ref operator*()
                {
                       return _node->_data;
                }

                Ptr operator->()
                {
                        return &_node->_data;
                }

                Self& operator++()
                {
                        _node = _node->_next;
                        return *this;
                }

                Self& operator--()
                {
                        _node = _node->_prev;
                        return *this;
                }

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

                Self operator--(int)
                {
                        Self tmp(*this);
                        _node = _node->_prev;
                        return tmp;
                }

                bool operator!=(const Self& s)
                {
                        return _node != s._node;
                }

                bool operator==(const Self& s)
                {
                        return _node == s._node;
                }
        };



                typedef list_iterator<T, T&, T*> iterator;
                typedef list_iterator<T, const T&, const T*> const_iterator;

      iterator begin()
                {
                        return iterator(_head->_next);
                }

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

                const_iterator begin() const
                {
                        return const_iterator(_head->_next);
                }

                const_iterator end() const
                {
                        return const_iterator(_head);
                } 四、insert

      iterator insert(iterator pos, const T& val)
                {
                        Node* cur = pos._node;
                        Node* newnode = new Node(val);
                        Node* prev = cur->_prev;

                        // prev newnode cur
                        prev->_next = newnode;
                        newnode->_prev = prev;

                        newnode->_next = cur;
                        cur->_prev = newnode;
                        ++_size;

                        return iterator(newnode);
                } 五、erase

      iterator erase(iterator pos)
                {
                        assert(pos != end());

                        Node* del = pos._node;
                        Node* prev = del->_prev;
                        Node* next = del->_next;

                        prev->_next = next;
                        next->_prev = prev;
                        delete del;

                        --_size;

                        return iterator(next);
                }
六、头(尾)插(删)

      void push_back(const T& x)
                {
                        /*Node* new_node = new Node(x);
                        Node* tail = _head->_prev;

                        tail->_next = new_node;
                        new_node->_prev = tail;

                        new_node->_next = _head;
                        _head->_prev = new_node;*/

                        insert(end(), x);
                }

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

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

                void pop_back()
                {
                        erase(--end());
                } 七、析构

      ~list()
                {
                        clear();

                        delete _head;
                        _head = nullptr;
                } 八、赋值运算符重载

      // lt2 = lt3
                //list& operator=(list lt)
                list<T>& operator=(list<T> lt)
                {
                        swap(lt);
                        return *this;
                } 九、clear

      void clear()
                {
                        auto it = begin();
                        while (it != end())
                        {
                                it = erase(it);
                        }
                }

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: list(c++)