• [C++入门]---List的使用及模拟实现


    1.list的介绍

    1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
    2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向 其前一个元素和后一个元素。
    3. listforward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
    4. 与其他的序列式容器相比(arrayvectordeque),list通常在任意位置进行插入、移除元素的执行效率更好。
    5. 与其他序列式容器相比,listforward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

    2.list的使用

    template < class T, class Alloc = allocator<T> > class list;
    //list的使用需要使用显示实例化才能使用
    
    • 1
    • 2

    2.1list的构造函数

    list (size_type n, const value_type& val = value_type())//构造的list中包含n个值为val的元素
    list()//构造空的list
    list (const list& x)//拷贝构造函数
    list (InputIterator first, InputIterator last)//用[first, last)区间中的元素构造list
    
    • 1
    • 2
    • 3
    • 4

    eg:

    void testlist1()
    {
    	list<int> lt1;
    	list<int> lt2(10, 6);
    	for (auto e : lt2)
    	{
    		cout << e << " ";
    	}
    	cout<<endl;
    	list<int> lt3(lt2);
    	for (auto e : lt3)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    	list<int> lt4(lt3.begin(), lt3.end());
    	for (auto e : lt4)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    代码运行结果为:

    2.2list modifiers

    void push_front (const value_type& val);
    //在首元素前插入值为val的元素
    void pop_front();
    //删除val的第一个元素
    void push_back (const value_type& val);
    //在list的尾部插入值为val的
    void pop_back();
    //删除list中最后一个元素
    single element (1)	
    iterator insert (iterator position, const value_type& val);
    //在list position位置插入值为val的元素
    fill (2)	
        void insert (iterator position, size_type n, const value_type& val);
    //在list position的位置插入n个值为val的元素
    range (3)	
    template <class InputIterator>
        void insert (iterator position, InputIterator first, InputIterator last);
    //在list position的位置插入[first,last]区间的元素
    iterator erase (iterator position);
    //删除position位置的值
    iterator erase (iterator first, iterator last);
    //删除[first,last)区间的元素
    void swap (list& x);
    //交换两个list中的元素
    void clear();
    //清空list中的数据
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    eg1:

    void testlist2()
    {
    	list<int> lt1;
    	lt1.push_back(10);
    	lt1.push_back(20);
    	lt1.push_back(30);
    	lt1.push_back(40);
    	lt1.push_back(50);
    	lt1.push_back(60);
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    	lt1.pop_front();
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    	lt1.push_front(100);
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    	lt1.pop_back();
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    代码编译运行的结果为:
    在这里插入图片描述
    eg2:

    void testlist3()
    {
    	list<int> lt1;
    	lt1.push_back(10);
    	lt1.push_back(20);
    	lt1.push_back(30);
    	lt1.push_back(40);
    	lt1.push_back(50);
    	lt1.push_back(60);
    	list<int>::iterator it = lt1.begin();
    	//在it位置插入99
    	lt1.insert(it, 99);
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    	it = lt1.begin();
    	//在it位置插入5个6
    	lt1.insert(it, 5, 6);
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    	it = lt1.begin();
    	list<int> lt2(6, 5);
    	lt1.insert(it, lt2.begin(), lt2.end());
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    代码编译运行的结果为:
    在这里插入图片描述
    eg3:

    void testlist4()
    {
    	list<int> lt1;
    	lt1.push_back(10);
    	lt1.push_back(20);
    	lt1.push_back(30);
    	lt1.push_back(40);
    	lt1.push_back(50);
    	lt1.push_back(60);
    	list<int>::iterator it = lt1.begin();
    	lt1.erase(it);
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    	lt1.erase(lt1.begin(), lt1.end());
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    代码编译运行的结果为:
    在这里插入图片描述
    eg4:

    void testlist5()
    {
    	list<int> lt1;
    	lt1.push_back(10);
    	lt1.push_back(20);
    	lt1.push_back(30);
    	lt1.push_back(40);
    	lt1.push_back(50);
    	lt1.push_back(60);
    	list<int> lt2(5, 6);
    	printf("lt1的当前元素:");
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    	printf("lt2的当前元素:");
    	for (auto& e : lt2)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    	swap(lt1, lt2);
    	printf("lt1的当前元素:");
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    	printf("lt2的当前元素:");
    	for (auto& e : lt2)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    代码编译运行的结果为:
    在这里插入图片描述
    eg5:

    void testlist6()
    {
    	list<int> lt1;
    	lt1.push_back(10);
    	lt1.push_back(20);
    	lt1.push_back(30);
    	lt1.push_back(40);
    	lt1.push_back(50);
    	lt1.push_back(60);
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    	//清空lt1原有数据后插入66
    	lt1.clear();
    	lt1.push_back(66);
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    代码编译运行的结果为:
    在这里插入图片描述

    2.3list capacity

    bool empty() const;
    //检测list是否为空,是返回true,否则返回false
    size_type size() const;
    //返回list中有效节点的个数
    
    • 1
    • 2
    • 3
    • 4

    2.4list elment access

    reference front();
    const_reference front() const;
    //返回list的第一个节点中值的引用
    reference back();
    const_reference back() const;
    //返回list的最后一个节点中值的引用
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    eg1:

    void testlist7()
    {
    	list<int> lt1;
    	lt1.push_back(10);
    	lt1.push_back(20);
    	lt1.push_back(30);
    	lt1.push_back(40);
    	lt1.push_back(50);
    	lt1.push_back(60);
    	cout << "list头部元素为:" << lt1.front() << endl;
    	cout << "list尾部元素为:" << lt1.back() << endl;	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    代码运行的结果为:
    在这里插入图片描述

    2.5iterator的使用

    iterator begin();
    const_iterator begin() const;
    //返回第一个元素的迭代器
    iterator end();
    const_iterator end() const;
    //返回最后一个元素下一个位置的迭代器
    reverse_iterator rbegin();
    const_reverse_iterator rbegin() const;
    //返回第一个元素的reverse_iterator,即end位置
    reverse_iterator rend();
    const_reverse_iterator rend() const;
    //返回最后一个元素下一个位置的reverse_iterator,即begin位置
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    list容器使用迭代器

    void testlist8()
    {
    	list<int> lt1(5, 6);
    	list<int>::iterator it = lt1.begin();	
    	while (it != lt1.end())
    	{
    		cout << *it <<" ";
    		it++;
    	}
    	cout << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    代码运行的结果为:
    在这里插入图片描述
    迭代器分类:

    input iterator//输入迭代器
    output iterator//输出迭代器
    forward iterator//单向迭代器可以++ 适用forward_list/unorderd_xxx容器
    bidirectional iterator//双向迭代器可以++/-- 适用list/map/set容器
    random access iteartor//任意迭代器可以++/--/+/- 适用于vector/string/deque容器
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    随机迭代器可以使用双向迭代器,反之双向迭代器不可以使用随机迭代器!较多功能的容器迭代器可以使用适配较少功能的迭代器的算法接口函数,反之则不可以!

    栗子:
    list的迭代器为:
    在这里插入图片描述
    算法接口函数为:
    在这里插入图片描述
    在这里插入图片描述

    void testlist9()
    {
    	list<int> lt1;
    	lt1.push_back(16);
    	lt1.push_back(8);
    	lt1.push_back(99);
    	lt1.push_back(18);
    	lt1.push_back(36);
    	lt1.push_back(6);
    	//不可以使用algorithm
    	//sort(lt1.begin(), lt1.end());
    	//可以使用list自己的sort进行排序
    	lt1.sort();
    	for (auto& e : lt1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    代码编译运行的结果为:
    在这里插入图片描述

    list的迭代器为双向迭代器,不能使用算法接口函数中适配任意迭代器的sort函数,只能使用list的sort函数

    3.list的模拟实现

    3.1list的源码

    #pragma once
    #include
    using namespace std;
    namespace newspace
    {
    	template<class T>
    	struct list_node
    	{
    		list_node<T>* _prev;
    		list_node<T>* _next;
    		T _val;
    
    		list_node(const T& val = T())
    			:_prev(nullptr)
    			, _next(nullptr)
    			, _val(val)
    		{}
    	};
    	template<class T,class Ref,class Ptr>
    	struct __list_iterator
    	{
    		typedef list_node<T> Node;
    		Node* _node;
    		typedef __list_iterator<T, Ref, Ptr> self;
    		__list_iterator(Node* node)
    			:_node(node)
    		{}
    
    		Ref operator*()
    		{
    			return _node->_val;
    		}
    
    		Ptr operator->()
    		{
    			return &_node->_val;
    		}
    		
    		//__list_iterator& operator++()
    		self& operator++()
    		{
    			_node = _node->_next;
    
    			return *this;
    		}
    		__list_iterator<T, Ref, Ptr> operator++(int)
    		//self operator++(int)
    		{
    			//__list_iterator tmp(*this);
    			self tmp(*this);
    			_node = _node->_next;
    
    			return tmp;
    		}
    		__list_iterator<T, Ref, Ptr>& operator--()
    		//self& operator--(int)
    		{
    			_node = _node->_prev;
    
    			return *this;
    		}
    		//__list_iterator operator--(int)
    		self operator--(int)
    		{
    			//__list_iterator tmp(*this);
    			self tmp(*this);
    			_node = _node->_prev;
    
    			return tmp;
    		}
    		bool operator==(const __list_iterator<T, Ref, Ptr>& it)
    		{
    			return _node == it._node;
    		}
    		bool operator!=(const __list_iterator<T, Ref, Ptr>& it)
    		{
    			return _node != it._node;
    		}
    	};
    	//template
    	//struct __list_const_iterator
    	//{
    	//	typedef list_node Node;
    	//	Node* _node;
    
    	//	__list_const_iterator(Node* node)
    	//		:_node(node)
    	//	{}
    
    	//	const T& operator*()
    	//	{
    	//		return _node->_val;
    	//	}
    
    	//	__list_const_iterator& operator++()
    	//	{
    	//		_node = _node->_next;
    
    	//		return *this;
    	//	}
    	//	__list_const_iterator& operator++(int)
    	//	{
    	//		__list_const_iterator tmp(*this);
    	//		_node = _node->_next;
    
    	//		return *this;
    	//	}
    	//	bool operator==(const __list_const_iterator& it)
    	//	{
    	//		return _node == it._node;
    	//	}
    	//	bool operator!=(const __list_const_iterator& it)
    	//	{
    	//		return _node != it._node;
    	//	}
    	//};
    
    	template<class T>
    	class list
    	{
    		typedef list_node<T> Node;
    	public:
    		typedef __list_iterator<T,T&,T*> iterator;
    		typedef __list_iterator<T,const T&,const T*> const_iterator;
    		//这样设计太冗余了
    		//typedef __list_const_iterator const_iterator;
    		
    		//这样设计const迭代器是不行的,因为const迭代器期望修饰内容不被修改
    		//这样设计迭代器本身不能修改
    		//typedef const _list_iterator const_iterator;
    		//如何设计const对象的iterator
    		//const T* ptr1;//ptr1本身不能修改
    		//T* const ptr2;//ptr2指向的内容不能修改
    		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(const list<T>& lt)
    		{
    			empty_init();
    			for (auto& e : lt)
    			{
    				push_back(e);
    			}
    		}
    		void swap(list<T>& lt)
    		{
    			std::swap(_head, lt._head);
    			std::swap(_size, lt._size);
    		}
    		const list<T>& operator=(list<T> lt)
    		{
    			swap(lt);
    			return *this;
    		}
    		void clear()
    		{
    			if (_head != nullptr)
    			{
    				iterator it = begin();
    				while (it != end())
    				{
    					it = erase(it);
    				}
    				_size = 0;
    			}
    		}
    		~list()
    		{
    			clear();
    			delete _head;
    			_head = nullptr;
    			_size = 0;
    		}
    		//void push_back(const T& x)
    		//{
    		//	Node* tail = new Node(x);
    		//	tail->_prev = _head->_prev;
    		//	tail->_prev->_next = tail;
    
    		//	_head->_prev = tail;
    		//	tail->_next = _head;
    		//}
    		void push_back(const T& x)
    		{
    			//Node* tail = _head->_prev;
    			//Node* newnode = new Node(x);
    			//newnode->_prev = tail;
    			//tail->_next = newnode;
    
    			//_head->_prev = newnode;
    			//newnode->_next = _head;
    			insert(end(), x);
    		}
    		void push_front(const T& x)
    		{
    			insert(begin(), x);
    		}
    		void pop_back()
    		{
    			erase(end()--);
    		}
    		void pop_front()
    		{
    			erase(begin());
    		}
    		//在pos位置插入数据
    		iterator insert(iterator pos, const T& x)
    		{
    			Node* cur = pos._node;
    			Node* prev = cur->_prev;
    			Node* newnode = new Node(x);
    			
    			prev->_next = newnode;
    			newnode->_prev = prev;
    
    			newnode->_next = cur;
    			cur->_prev = newnode;
    			++_size;
    			return newnode;
    		}
    		//删除pos位置的数据
    		iterator erase(iterator pos)
    		{
    			assert(pos != end());
    			Node* cur = pos._node;
    			Node* prev = cur->_prev;
    			Node* next = cur->_next;
    
    			prev->_next = next;
    			next->_prev = prev;
    			--_size;
    			delete cur;
    
    			return next;
    		}
    		size_t size()const
    		{
    			//const_iterator it = begin();
    			//size_t size = 0;
    			//while (it != end())
    			//{
    			//	size++;
    			//	it++;
    			//}
    			//return size;
    			return _size;
    		}
    	private:
    		Node* _head;
    		size_t _size;
    	};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
  • 相关阅读:
    解释 Vue 组件的各个生命周期钩子函数及其用途
    ​MPV,汽车产品里一个特殊品类的进化过程
    iOS Bug 收集
    EN 12259-2固定消防系统湿式报警阀组件—CE认证
    7-5 表格输出(分数 5)与7-6 混合类型数据格式化输入(分数 5)
    Java框架(七)-- RESTful风格的应用(2)--简单请求与非简单请求、JSON序列化
    JuiceFS 在多云存储架构中的应用 | 深势科技分享
    Git基础教程详解
    衡水袁隆平旱稻试验田 国稻种芯·中国水稻节:河北节水增收
    知识图谱和 LLM:利用 Neo4j 实现大型语言模型
  • 原文地址:https://blog.csdn.net/m0_74288306/article/details/132916531