C++: Introduction and simulation implementation of stl_List

Table of contents

1. List definition

2. Use of List

(1) Traversal after push_back

(2) Erase and insert are used the same as vector, there is nothing to say.

(3) sort (List supports sorting, but the efficiency is low)

【1】Introduction List::sort

[2] The reason why sort in the library does not support List (three types of iterators: bidirectional iterators - newly added):

【3】Comparing std::sort with List::sort, List::sort is a "flying house"

3. List simulation implementation

Key points:

(1) return iterator(_head->_next); returns an anonymous object

(2) Can the begin() iterator directly return _head->_next? --Can

(3) it->_a1 explanation

(4) Why should list encapsulate a new iterator instead of using a native pointer? vector can

(5) const iterator

(6) Erase iterator fails

1. The first stage

List.h

Test.cpp

2. Second stage const iterator

List.h

3. The third stage

Common mistakes:

4. List of related topics


1. List definition

Lists are sequence containers that allow constant time insert and erase operations anywhere within the sequence, and iteration in both directions.

List is a sequential container that allows arbitrary insertion and deletion with O(1) time complexity, and also supports bidirectional iterators. (The bottom layer of List is a two-way headed linked list)

2. Use of List

(1) Traversal after push_back

The bottom layer of List is a linked list. The space of the linked list is not continuous, so the traversal method of [] + subscript is abandoned, and iterator traversal is usually used.

void test_list1()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);

		list<int>::iterator it = lt.begin();
		while (it != lt.end())        //迭代器遍历
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
    
		for (auto e : lt)            //范围for遍历
		{
			cout << e << " ";
		}
		cout << endl;

		//list<int>::reverse_iterator rit = lt.rbegin();
		auto rit = lt.rbegin();
		while (rit != lt.rend())
		{
			cout << *rit << " ";
			++rit;
		}
		cout << endl;

	}

(2) Erase and insert are used the same as vector, there is nothing to say.

(3) sort (List supports sorting, but the efficiency is low)

【1】Introduction List::sort

The sort in the library does not support List, so List must have its own sort (the reason is as follows). Due to structural problems, List::sort is very inefficient. Sorting vectors with std::sort will be very fast. It is not recommended to use List:: sort.

void test_list3()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_front(10);
		lt.push_front(20);
		lt.push_front(30);
		lt.push_front(40);

		lt.push_back(1);
		lt.push_back(1);
		lt.push_back(1);

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;

		lt.sort();
		lt.unique();

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}

[2] The reason why sort in the library does not support List (three types of iterators: bidirectional iterators - newly added):

From the perspective of implementation structure, iterators are actually divided into three categories:
1. One-way iterators. Only ++ operations can be performed
2. Bidirectional iterator. Only ++, -- operation
3, random iterator can be performed. Only ++, --, +, - operations can be performed

Random iterator inherits all the functions of bidirectional iterator, so random iterator can also be passed where bidirectional iterator is required.

Bidirectional iterators inherit unidirectional iterators, and bidirectional or random iterators can also be passed where unidirectional iterators are required.

But where a random iterator needs to be passed, only a random iterator can be passed.

Random iterators belong to one-way iterators and two-way iterators, that is, one-way iterators include random iterators, and two-way iterators also include random iterators.

sort in the library is a random iterator

List is a bidirectional iterator

Two-way includes random, but random does not include two-way, so the use of std::sort cannot include two-way

【3】Comparing std::sort with List::sort, List::sort is a "flying house"

The bottom layer of std::sort is quick sort (the header file <algorithm> must be included)

The bottom layer of List::sort is merge sort

 

Summary: In the case of short data (within 10,000 pieces of data) List::sort is valuable and can be used. For big data, vector sorting is needed, which has the advantage of continuous space. 

3. List simulation implementation

Key points:

(1) return iterator(_head->_next); returns an anonymous object

iterator() is an anonymous object. The anonymous object only exists in the line of code that constructs the object. The destructor is called immediately after leaving the line of code that constructs the anonymous object.

①return iterator(_head->_next); This sentence is equivalent to: ②Construct an it object of the iterator class first . Because it is not returned by reference, a temporary copy of it needs to be returned. The temporary copy is obtained by it copy construction .

②iterator it( head-> next);     
    return it;

Comparison: ② After constructing the object it, and then copy-constructing a temporary variable; ① Using anonymous object optimization: Optimizing the construction of anonymous objects + copy-constructing temporary variables into directly constructing an object and returning it.

        iterator begin()
		{
			return iterator(_head->_next);    //iterator()是匿名对象,详情看(1)
			//return _head->_next;
		}

		iterator end()
		{
			return iterator(_head);      //iterator()是匿名对象,详情看(1)
		}

(2) Can the begin() iterator directly return _head->_next? --Can

The single-parameter constructor supports implicit type conversion: the return value is an iterator. Originally, an object of the iterator class was constructed first, and then a temporary variable was copied and constructed. Through compiler optimization, an object is directly constructed and returned.

        iterator begin()
		{
			return iterator(_head->_next);    //iterator()是匿名对象,详情看(1)
			//return _head->_next; //能否直接返回  _head->_next ?——可以,详情看(2)
		}

(3) it->_a1 explanation

cout << (*it)._a1 << "-"<< (*it)._a2 <<" "; Accessing the data in AA is a normal operation, and it->_a1 can also be accessed using pointer pointing method. Because *it returns _node->_data, so it-> returns &_node->_data. Logically speaking, the way to access AA data elements using pointer pointing should be it->->_a1. The compiler does this for readability. Optimization processing. After optimization, one -> is omitted and becomes it->_a1.

struct __list_iterator中:
        T& operator*()
		{
			return _node->_data;
		}

        T* operator->()
		{ 
			//return &(operator*());
			return &_node->_data;
		}

	void test_list2()
	{
		list<AA> lt;
		lt.push_back(AA(1, 1));
		lt.push_back(AA(2, 2));
		lt.push_back(AA(3, 3));
		lt.push_back(AA(4, 4));

		// 迭代器模拟的是指针行为
		// int* it  *it
		// AA*  it  *it  it->
		list<AA>::iterator it = lt.begin();
		while (it != lt.end())
		{
			//cout << (*it)._a1 << "-"<< (*it)._a2 <<" ";
			cout << it->_a1 << "-" << it->_a2 << " ";    //it->_a1解释,详情见(3)
			++it;
		}
		cout << endl;
	}

(4) Why should list encapsulate a new iterator instead of using a native pointer? vector can

template<class T>
	struct __list_iterator  //详情见(3),list为什么不能用原生指针?因为物理空间不连续
	{……}

 Vector is equivalent to a child who has a mine at home, no need to work hard, the family will provide it (the system supports ++--, etc. with native pointers as iterators).

list is equivalent to an ordinary family and requires your own efforts (write your own custom type to support the iterator __list_iterator, and overload operators)

The appearance (call) of the two looks exactly the same, but the actual bottom layer is completely different.

(5) const iterator

In order to support the transfer of const objects in formal parameters like printf, the normal idea is to copy the __list_iterator class again, and then change all of them to const to make the __list_const_iterator class. However, this is not reusable and is not easy to maintain, so we use templates Control const type parameters: Anyway, it is a change to operator* and -> return value. It is better to directly add two template parameters T& and T*, divided into const and non-const templates. When the lt object is const, the const_iterator template is used; when the object is non-const, the iterator template is used. When calling lt.begin(), the temporary object type returned by begin() is const_iterator, then the three template types passed in by __list_iterator are const_iterator,

That is, __list_iterator<T, const T&, const T*>

	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
		// *it
		Ref operator*()
		{
			return _node->_data;
		}

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

    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;

		const_iterator begin() const
		{
			// list_node<int>*
			return const_iterator(_head->_next);
		}

		const_iterator end() const
		{
			return const_iterator(_head);
		}
    ……

	void print_list(const list<int>& lt)
	{
		list<int>::const_iterator it = lt.begin();
		while (it != lt.end())
		{
			//*it = 10; // 不允许修改
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

(6) Erase iterator fails

Insert will not cause the iterator to expire. No matter how it is inserted, iterator pos points to the original position. It's just that the return value is an iterator to return the new node.

Erase will cause the iterator to become invalid. As long as the node at pos is deleted, pos will become a wild pointer.

1. The first stage

List.h

#pragma once
namespace bit
{
	template<class T>
	struct list_node
	{
		list_node<T>* _next;
		list_node<T>* _prev;
		T _data;

		list_node(const T& val = T())
			:_next(nullptr)
			, _prev(nullptr)
			, _data(val)
		{}
	};

	template<class T>
	struct __list_iterator  //详情见(4),list为什么不能用原生指针?因为物理空间不连续
	{
		typedef list_node<T> Node;
		typedef __list_iterator<T> self;
		Node* _node;

		__list_iterator(Node* node)    //这里写构造函数是为了传参,默认生成的构造函数无法传参
			:_node(node)
		{}

		// 析构函数  -- 节点不属于迭代器,不需要迭代器释放
		// 拷贝构造和赋值重载 -- 默认生成的浅拷贝就可以

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

		T* operator->()
		{ 
			//return &(operator*());
			return &_node->_data;
		}

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

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

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

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


		bool operator!=(const self& it)
		{
			return _node != it._node;
		}

		bool operator==(const self& it)
		{
			return _node == it._node;
		}

	};

	template<class T>
	class list
	{
		typedef list_node<T> Node;
	public:
		typedef __list_iterator<T> iterator;

		iterator begin()
		{
			return iterator(_head->_next);    //iterator()是匿名对象,详情看(1)
			//return _head->_next; //能否直接返回  _head->_next ?——可以,详情看(2)
		}

		iterator end()
		{
			return iterator(_head);      //iterator()是匿名对象,详情看(1)
		}

		list()
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
		}

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

			// _head       tail  newnode
			tail->_next = newnode;
			newnode->_prev = tail;
			newnode->_next = _head;
			_head->_prev = newnode;
		}

	private:
		Node* _head;
	};

	void test_list1()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);

		list<int>::iterator it = lt.begin();
		while (it != lt.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

	struct AA
	{
		AA(int a1 = 0, int a2 = 0)
			:_a1(a1)
			, _a2(a2)
		{}

		int _a1;
		int _a2;
	};

	void test_list2()
	{
		list<AA> lt;
		lt.push_back(AA(1, 1));
		lt.push_back(AA(2, 2));
		lt.push_back(AA(3, 3));
		lt.push_back(AA(4, 4));

		// 迭代器模拟的是指针行为
		// int* it  *it
		// AA*  it  *it  it->
		list<AA>::iterator it = lt.begin();
		while (it != lt.end())
		{
			//cout << (*it)._a1 << "-"<< (*it)._a2 <<" ";
			cout << it->_a1 << "-" << it->_a2 << " ";    //it->_a1解释,详情见(3)
			++it;
		}
		cout << endl;
	}
}

Test.cpp

int main()
{
	bit::test_list2();

	return 0;
}

2. Second stage const iterator

List.h

#pragma once
#include <assert.h>

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

		list_node(const T& val = T())
			:_next(nullptr)
			, _prev(nullptr)
			, _data(val)
		{}
	};

	// typedef __list_iterator<T, T&, T*> iterator;
	// typedef __list_iterator<T, const T&, const T*> const_iterator;

	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)
		{}

		// 析构函数  -- 节点不属于迭代器,不需要迭代器释放
		// 拷贝构造和赋值重载 -- 默认生成的浅拷贝就可以

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

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

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

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

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

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


		bool operator!=(const self& it)
		{
			return _node != it._node;
		}

		bool operator==(const self& it)
		{
			return _node == it._node;
		}

	};

	// 复用性很差
	// 单独实现一个类,支持不能修改迭代器指向节点的数据
	//template<class T>
	//struct __list_const_iterator;



	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;

		const_iterator begin() const
		{
			// list_node<int>*
			return const_iterator(_head->_next);
		}

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

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

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

		list()
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
		}

		// lt2(lt1)
		/*list(const list<T>& lt)
		{
		_head = new Node();
		_head->_next = _head;
		_head->_prev = _head;

		for (auto e : lt)
		{
		push_back(e);
		}
		}*/

		void empty_init()
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
		}

		template <class InputIterator>
		list(InputIterator first, InputIterator last)
		{
			empty_init();

			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		// 17:00 继续
		void swap(list<T>& lt)
		{
			std::swap(_head, lt._head);
		}

		// lt2(lt1) -- 现代写法
		list(const list<T>& lt)
		{
			empty_init();
			list<T> tmp(lt.begin(), lt.end());
			swap(tmp);
		}

		// lt2 = lt1
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}

		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}

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

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

			 _head       tail  newnode
			//tail->_next = newnode;
			//newnode->_prev = tail;
			//newnode->_next = _head;
			//_head->_prev = newnode;

			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* newNode = new Node(x);
			Node* cur = pos._node;
			Node* prev = cur->_prev;

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

			return iterator(newNode);
		}

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

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

			// prev  next
			prev->_next = next;
			next->_prev = prev;
			delete cur;

			return iterator(next);
		}

	private:
		Node* _head;
	};

	void print_list(const list<int>& lt)
	{
		list<int>::const_iterator it = lt.begin();
		while (it != lt.end())
		{
			//*it = 10; // 不允许修改
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

3. The third stage

Common mistakes:

The assert in erase is missing, clear must be implemented with an iterator, the list constructor is overloaded and the empty_init() function is missing. Swap should use the swap in the library to exchange nodes. The swap function cannot use const (otherwise it cannot be changed, that is, it cannot be swapped) , operator=parameter cannot have a reference

Added content: insert, erase, head-to-tail insertion, head-to-tail deletion, clear, destructor, 1 overload of constructor, copy construction (2 ancient and modern writing methods), assignment operator overloading (1 modern writing method)

The copy structure of the linked list requires deep copy. If it is shallow copy, the head node _head of the two linked lists will point to the same linked list.

#pragma once
#include <assert.h>

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

		list_node(const T& val = T())
			:_next(nullptr)
			, _prev(nullptr)
			, _data(val)
		{}
	};

	// typedef __list_iterator<T, T&, T*> iterator;
	// typedef __list_iterator<T, const T&, const T*> const_iterator;

	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)
		{}

		// 析构函数  -- 节点不属于迭代器,不需要迭代器释放
		// 拷贝构造和赋值重载 -- 默认生成的浅拷贝就可以

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

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

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

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

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

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


		bool operator!=(const self& it)
		{
			return _node != it._node;
		}

		bool operator==(const self& it)
		{
			return _node == it._node;
		}

	};

	// 复用性很差
	// 单独实现一个类,支持不能修改迭代器指向节点的数据
	//template<class T>
	//struct __list_const_iterator;



	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;

		const_iterator begin() const
		{
			// list_node<int>*
			return const_iterator(_head->_next);
		}

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

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

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

		list()
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
		}

		void empty_init()
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
		}

        //这是构造函数,是使用lt的值来进行构造的
		template <class InputIterator>
		list(InputIterator first, InputIterator last)
		{        
			empty_init();

			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

        // lt2(lt1)    拷贝构造远古写法
		/*list(const list<T>& lt)
		{
		_head = new Node();
		_head->_next = _head;
		_head->_prev = _head;

		for (auto e : lt)
		{
		push_back(e);
		}
		}*/

		// 17:00 继续
		void swap(list<T>& lt)    //不能加const,要不然修改不了了
		{
			std::swap(_head, lt._head);
		}

		// lt2(lt1) -- 拷贝构造现代写法
//链表的拷贝构造要深拷贝,如果浅拷贝就会导致两个链表的头结点_head指向同一个链表
		list(const list<T>& lt)
		{
			empty_init();
			list<T> tmp(lt.begin(), lt.end());
			swap(tmp);
		}

		// lt2 = lt1
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}

		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}

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

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

			 _head       tail  newnode
			//tail->_next = newnode;
			//newnode->_prev = tail;
			//newnode->_next = _head;
			//_head->_prev = newnode;

			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* newNode = new Node(x);
			Node* cur = pos._node;
			Node* prev = cur->_prev;

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

			return iterator(newNode);
		}

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

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

			// prev  next
			prev->_next = next;
			next->_prev = prev;
			delete cur;

			return iterator(next);
		}

	private:
		Node* _head;
	};

	void print_list(const list<int>& lt)
	{
		list<int>::const_iterator it = lt.begin();
		while (it != lt.end())
		{
			//*it = 10; // 不允许修改
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

	void test_list1()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);

		list<int>::iterator it = lt.begin();
		while (it != lt.end())
		{
			*it = 20;
			cout << *it << " ";
			++it;
		}
		cout << endl;

		print_list(lt);
	}

	struct AA
	{
		AA(int a1 = 0, int a2 = 0)
			:_a1(a1)
			, _a2(a2)
		{}

		int _a1;
		int _a2;
	};

	void test_list2()
	{
		list<AA> lt;
		lt.push_back(AA(1, 1));
		lt.push_back(AA(2, 2));
		lt.push_back(AA(3, 3));
		lt.push_back(AA(4, 4));

		// 迭代器模拟的是指针行为
		// int* it  *it
		// AA*  it  *it  it->
		list<AA>::iterator it = lt.begin();
		while (it != lt.end())
		{
			//cout << (*it)._a1 << "-"<< (*it)._a2 <<" ";
			cout << it->_a1 << "-" << it->_a2 << " ";
			++it;
		}
		cout << endl;
	}


	void test_list3()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);

		lt.push_front(1);
		lt.push_front(2);
		lt.push_front(3);
		lt.push_front(4);
		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;

		lt.pop_front();
		lt.pop_front();

		lt.pop_back();
		lt.pop_back();

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_list4()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);
		lt.push_back(6);

		// 要求在偶数的前面插入这个偶数*10
		auto it1 = lt.begin();
		while (it1 != lt.end())
		{
			if (*it1 % 2 == 0)
			{
				lt.insert(it1, *it1 * 10);
			}

			++it1;
		}

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_list5()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);
		lt.push_back(6);

		// 删除所有的偶数
		/*auto it1 = lt.begin();
		while (it1 != lt.end())
		{
			if (*it1 % 2 == 0)
			{
				lt.erase(it1);
			}

			++it1;
		}*/

		auto it1 = lt.begin();
		while (it1 != lt.end())
		{
			if (*it1 % 2 == 0)
			{
				it1 = lt.erase(it1);
			}
			else
			{
				++it1;
			}
		}

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;

		lt.clear();

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;

		lt.push_back(10);
		lt.push_back(20);
		lt.push_back(30);

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_list6()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);
		lt.push_back(6);

		list<int> lt1(lt);

		for (auto e : lt1)
		{
			cout << e << " ";
		}
		cout << endl;

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;

		list<int> lt2;
		lt2.push_back(10);
		lt2.push_back(20);
		lt1 = lt2;
		for (auto e : lt2)
		{
			cout << e << " ";
		}
		cout << endl;

		for (auto e : lt1)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}

4. List of related topics

for (int i=1; i<10; ++i) myvector.push_back(i);   // 1 2 3 4 5 6 7 8 9

std::reverse(myvector.begin(),myvector.end());    // 9 8 7 6 5 4 3 2 1

可知std::reserve is to reverse the position from the beginning of the iterator to the end.

Guess you like

Origin blog.csdn.net/zhang_si_hang/article/details/126011527