欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 艺术 > C++——list

C++——list

2024/10/24 15:16:07 来源:https://blog.csdn.net/2301_79998744/article/details/142711429  浏览:    关键词:C++——list

文章目录

  • 一、list的介绍及使用
    • 1.list的介绍
    • 2.list的使用
      • 2.1 构造
      • 2.2 迭代器
      • 2.3 空间
      • 2.4 节点访问
      • 2.5 修改
  • 二、迭代器失效
  • 三、list的模拟实现
    • 3.1 基本结构
    • 3.2 构造和析构
    • 3.3 迭代器
    • 3.4 空间
    • 3.5 修改
    • 3.6 源代码
      • list.h
      • list.cpp
  • 四、list与vector的对比

一、list的介绍及使用

1.list的介绍

list

c++中list为双向带头循环列表

在这里插入图片描述

2.list的使用

2.1 构造

在这里插入图片描述

#include <iostream>
using namespace std;
#include <list>
#include <vector>// list的构造
void TestList1()
{list<int> l1;                         // 构造空的l1list<int> l2(4, 100);                 // l2中放4个值为100的元素list<int> l3(l2.begin(), l2.end());  // 用l2的[begin(), end())左闭右开的区间构造l3list<int> l4(l3);                    // 用l3拷贝构造l4// 以数组为迭代器区间构造l5int array[] = { 16,2,77,29 };list<int> l5(array, array + sizeof(array) / sizeof(int));// 列表格式初始化C++11list<int> l6{ 1,2,3,4,5 };// 用迭代器方式打印l5中的元素list<int>::iterator it = l5.begin();while (it != l5.end()){cout << *it << " ";++it;}       cout << endl;// C++11范围for的方式遍历for (auto& e : l5)cout << e << " ";cout << endl;
}

2.2 迭代器

注意:list的迭代器不支持+,- 操作符

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

注意:

  1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

  2. rbegin(end)与rend(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[0]));// 使用正向迭代器正向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;
}

2.3 空间

在这里插入图片描述

2.4 节点访问

在这里插入图片描述

2.5 修改

在这里插入图片描述

// 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[0]));// 在list的尾部插入4,头部插入0L.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[0]));// 获取链表中第二个节点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);
}

二、迭代器失效

可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。

因为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[0]));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[0]));auto it = l.begin();while (it != l.end()){l.erase(it++); // it = l.erase(it);}
}

三、list的模拟实现

3.1 基本结构

template<class T>
struct list_node
{list_node(const T& date = T()):_date(date),_prev(nullptr),_next(nullptr){}T _date;list_node<T>* _prev;list_node<T>* _next;
};template<class T>
class list
{typedef list_node<T> Node;
private:Node* _head;size_t _size;
};

3.2 构造和析构

void empty_init()
{_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;
}list()
{empty_init();
}list(initializer_list<T> il)
{empty_init();for (auto& e : il){push_back(e);}
}list(const list<T>& l1)
{empty_init();for (auto& e : l1){push_back(e);}
}~list()
{clear();delete _head;_head = nullptr;
}

3.3 迭代器

由于list的储存空间不是连续的,所以我们要单独实现++/–等操作,所以我们直接放在一个类中去实现它

template<class T>
struct list_iterator
{typedef list_node<T> Node;typedef list_iterator<T> Self;Node* _node;list_iterator(Node* node){_node = node;}T& operator*(){return _node->_date;}T* operator->(){return &_node->_date;}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) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}
};

但是这样写太过麻烦,我们看库里面是如何实现的
在这里插入图片描述

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->_date;}Ptr operator->(){return &_node->_date;}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) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}
};

在list里面这样写,就方便了很多

typedef list_iterator<T,T&,T*> iterator;
typedef list_iterator<T,const T&, const T*> const_iterator;
iterator begin()
{return _head->_next;
}
iterator end()
{return _head;
}const_iterator begin() const
{return _head->_next;
}
const_iterator end() const
{return _head;
}

3.4 空间

size_t size() const
{return _size;
}bool empty() const
{return _size == 0;
}

3.5 修改

list<T>& operator=(list<T> l1)
{swap(l1);return *this;
}void swap(list<T> tmp)
{std::swap(_head, tmp._head);std::swap(_size, tmp._size);
}void push_back(const T& x)
{/*Node* newnode = new Node(x);Node* tail = _head->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;++_size;*/insert(end(), x);
}void push_front(const T& x)
{insert(begin(), x);
}iterator insert(iterator pos, const T& x)
{Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);//prev newnode curnewnode->_next = cur;newnode->_prev = prev;prev->_next = newnode;cur->_prev = newnode;++_size;return newnode;
}void pop_back()
{erase(--end());
}void pop_front()
{erase(begin());
}iterator erase(iterator pos)
{assert(pos != end());Node* prev = pos._node->_prev;Node* next = pos._node->_next;prev->_next = next;next->_prev = prev;delete pos._node;pos._node = nullptr;--_size;return next;
}void clear()
{auto it = begin();while (it != end()){it = erase(it);}
}

3.6 源代码

list.h

#pragma once
#include <iostream>
#include <assert.h>
#include <list>
using namespace std;
namespace mihayou
{template<class T>struct list_node{list_node(const T& date = T()):_date(date),_prev(nullptr),_next(nullptr){}T _date;list_node<T>* _prev;list_node<T>* _next;};/*template<class T>struct list_iterator{typedef list_node<T> Node;typedef list_iterator<T> Self;Node* _node;list_iterator(Node* node){_node = node;}T& operator*(){return _node->_date;}T* operator->(){return &_node->_date;}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) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}};*//*template<class T>struct list_const_iterator{typedef list_node<T> Node;typedef list_const_iterator<T> Self;Node* _node;list_const_iterator(Node* node){_node = node;}const T& operator*(){return _node->_date;}const T* operator->(){return &_node->_date;}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) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}};*/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->_date;}Ptr operator->(){return &_node->_date;}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) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}};template<class T>class list{typedef list_node<T> Node;public:/*typedef list_iterator<T> iterator;typedef list_const_iterator<T> const_iterator;*/typedef list_iterator<T,T&,T*> iterator;typedef list_iterator<T,const T&, const T*> const_iterator;iterator begin(){return _head->_next;}iterator end(){return _head;}const_iterator begin() const{return _head->_next;}const_iterator end() const{return _head;}void empty_init(){_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;}list(){empty_init();}list(initializer_list<T> il){empty_init();for (auto& e : il){push_back(e);}}list(const list<T>& l1){empty_init();for (auto& e : l1){push_back(e);}}list<T>& operator=(list<T> l1){swap(l1);return *this;}void swap(list<T> tmp){std::swap(_head, tmp._head);std::swap(_size, tmp._size);}void push_back(const T& x){/*Node* newnode = new Node(x);Node* tail = _head->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;++_size;*/insert(end(), x);}void push_front(const T& x){insert(begin(), x);}iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);//prev newnode curnewnode->_next = cur;newnode->_prev = prev;prev->_next = newnode;cur->_prev = newnode;++_size;return newnode;}void pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator erase(iterator pos){assert(pos != end());Node* prev = pos._node->_prev;Node* next = pos._node->_next;prev->_next = next;next->_prev = prev;delete pos._node;pos._node = nullptr;--_size;return next;}size_t size() const{return _size;}bool empty() const{return _size == 0;}~list(){clear();delete _head;_head = nullptr;}void clear(){auto it = begin();while (it != end()){it = erase(it);}}private:Node* _head;size_t _size;};//按需实例化template<class Container>void print_container(const Container& con){//const iterator -> 迭代器本身不能修改//const_iterator -> 指向内容不能改变//typename Container::const_iterator it = con.begin();auto it = con.begin();while (it != con.end()){//*it += 10;cout << *it << " ";it++;}cout << endl;/*for (auto e : con){cout << e << " ";}cout << endl;*/}
}

list.cpp

#include "list.h"namespace mihayou
{struct AA{int _a1 = 1;int _a2 = 1;};void test01(){list<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_front(6);v1.pop_back();v1.pop_front();auto itt = v1.begin();int k = 1;while (k--){++itt;}v1.erase(itt);list<int>::iterator it = v1.begin();while (it != v1.end()){*it += 10;cout << *it << " ";++it;}cout << endl;print_container(v1);list<AA> aa;aa.push_back(AA());aa.push_back(AA());aa.push_back(AA());aa.push_back(AA());list<AA>::iterator ita = aa.begin();while (ita != aa.end()){cout << ita->_a1 << " " << ita->_a2 << " ";//cout << ita.operator->()->_a1 << " " << ita.operator->()->_a2 << " ";++ita;}cout << endl;}void test02(){list<int> l1;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);//insert以后迭代器不失效list<int>::iterator it = l1.begin();l1.insert(it,10);*it += 10;print_container(l1);//erase以后迭代器不失效auto itt = l1.begin();while (itt != l1.end()){if (*itt % 2 == 0){itt = l1.erase(itt);}else{itt++;}}print_container(l1);}void test03(){list<int> l1;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);print_container(l1);list<int> l2(l1);print_container(l2);list<int> l3;l3 = l1;print_container(l3);}void fun(const list<int>& lt){print_container(lt);}void test04(){list<int> l0({ 1,2,3,4 });//隐式类型转换list<int> l1 = { 1,2,3,4 };print_container(l1);const list<int>& l2  = { 1,2,3,4 };fun(l1);fun({ 1,2,3,4 });//auto l1 = { 1,2,3,4 };/*initializer_list<int> l1 = { 1,2,3,4 };cout << typeid(l1).name() << endl;cout << sizeof(l1) << endl;*/}
}int main()
{mihayou::test01();return 0;
}

四、list与vector的对比

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com