【C++】第九节:list

1、list的介绍及使用

1.1 list的介绍

list - C++ 参考

1.2 list的使用

1.2.1 list的构造

cpp 复制代码
void TestList1()
{
	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 arr[] = { 16,2,77,29 };
	list<int> l5(arr, arr + sizeof(arr) / sizeof(int));

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

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

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

1.2.2 list iterator的使用

cpp 复制代码
// 注意:遍历链表只能用迭代器和范围for
void TestList2()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,0 };
	list<int> l(arr, arr + sizeof(arr) / sizeof(arr[0]));

	// 使用正向迭代器遍历
	list<int>::iterator it = l.begin();
	while (it != l.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	// 使用反向迭代器遍历
	list<int>::reverse_iterator rit = l.rbegin();
	while (rit != l.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;

	// 使用for循环遍历
	// 注意这里调用的是list的begin() const,返回list的const_iterator对象
	for (list<int>::const_iterator cit = l.begin(); cit != l.end(); ++cit)
	{
		cout << *cit << " ";
		//*cit = 10; // 编译不通过
	}
	cout << endl;
}

1.2.3 list capacity

1.2.4 list element access

1.2.5 list modifiers

cpp 复制代码
void TestList3()
{
	int arr[] = { 1,2,3 };
	list<int> l(arr, arr + sizeof(arr) / sizeof(arr[0]));

	// 在l的尾部插入4,头部插入0
	l.push_back(4);
	l.push_front(0);
	for (auto& e : l)
	{
		cout << e << " ";
	}
	cout << endl;

	// 获取链表第二个节点
	auto pos = ++l.begin();

	// 在pos位置之前插入7
	l.insert(pos, 7);

	// 用迭代器区间插入
	vector<int> v{ 4,5,6 };
	l.insert(pos, v.begin(), v.end());
	for (auto& e : l)
	{
		cout << e << " ";
	}
	cout << endl;

	// 删除pos位置上的元素
	l.erase(pos);
	for (auto& e : l)
	{
		cout << e << " ";
	}
	cout << endl;
}
cpp 复制代码
void TestList4()
{
	int arr[] = { 1,2,3 };
	list<int> l1(arr, arr + sizeof(arr) / sizeof(arr[0]));

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

	for (auto& e : l1)
	{
		cout << e << " ";
	}
	cout << endl;
	for (auto& e : l2)
	{
		cout << e << " ";
	}
	cout << endl;

	// 清空l2中的元素
	l2.clear();
	cout << l2.size() << endl;
}

1.2.6 list operations

cpp 复制代码
void TestList5()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(5);

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

	lt.reverse();

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

	//sort(lt.begin(), lt.end()); // 报错,因为list底层是双向迭代器,而sort需要随机迭代器

	// 升序 < less
	//lt.sort(); 
	// 降序 > greater
	//greater<int> gt;
	//lt.sort(gt);
	lt.sort(greater<int>()); // 匿名对象

	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
}
cpp 复制代码
void TestList6();
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(3);
	lt.push_back(3);
	lt.push_back(3);
	lt.push_back(5);
	lt.push_back(5);
	lt.push_back(3);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	lt.sort(); // 先排序
	lt.unique();// 再去重
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

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

1.2.7 list迭代器失效

此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点无效,即该节点被删除了。因为 list 的底层结构为带头结点的双向循环链表,因此在 list 中进行插入时是不会导致迭代器失效的,只有删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

cpp 复制代码
void TestListIterator1()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	list<int> l(arr, arr + sizeof(arr) / sizeof(arr[0]));
	auto it = l.begin();
	while (it != l.end())
	{
		// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值
		l.erase(it);
		++it;
	}
}

// 改正
void TestListIterator()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	list<int> l(arr, arr + sizeof(arr) / sizeof(arr[0]));
	auto it = l.begin();
	while (it != l.end())
	{
		l.erase(it++); // it++作为参数传递给l.erase()
	}
}

2、list的模拟实现

2.1 模拟实现list

cpp 复制代码
namespace yf
{
	// list的节点类(模板类)
	template<class T>
	struct list_node
	{
		T _data;
		list_node<T>* _next;
		list_node<T>* _prev;

		// T不一定是int,所以不能直接给0,要用匿名对象
		list_node(const T& x = T()) 
			:_data(x)
			, _next(nullptr)
			, _prev(nullptr)
		{}
	};

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

		// 前置++
		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;
		}

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

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

		// 用于比较两个迭代器是否相等
		bool operator!=(const self& s)
		{
			return _node != s._node; // !=运算符是内置的指针比较运算符
		}

		bool operator==(const self& s)
		{
			return _node == s._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;

		const_iterator begin() const
		{
			// 这里跳到迭代器的构造函数创建了一个新的const_iterator对象,
			// 使其指向_head->_next节点
			return const_iterator(_head->_next);
		}

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

		iterator begin()
		{
			//return iterator(_head->_next);
			return _head->_next; // list_node<T>*会被隐式类型转换为iteator对象
		}

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

		// 空初始化
		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;

			_size = 0;
		}

		// 无参构造函数
		list()
		{
			empty_init();
		}

		// lt2(lt1)
		list(const list<T>& lt)
		{
			// 先构造一个空的lt2
			empty_init();
			for (auto e : lt)
			{
				push_back(e);
			}
		}

		void swap(list<int>& lt)
		{
			std::swap(_head, lt._head);
			std::swap(_size, lt._size);
		}

		// lt3 = lt2
		list<int>& operator=(list<int> lt)
		{
			swap(lt);

			return *this;
		}

		~list()
		{
			clear();

			delete _head;
		}

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

		void push_back(const T& x)
		{
			insert(end(), x);
		}

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

		void pop_back()
		{
			erase(--end());
		}

		// 在pos位置之前插入,返回新插入的位置
		iterator insert(iterator pos, const T& x)
		{
			Node* cur = pos._node;
			Node* newnode = new Node(x);

			Node* prev = cur->_prev;

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

			++_size;

			return iterator(newnode);
		}

		// 删除pos节点,返回pos节点的下一个节点的迭代器
		iterator erase(iterator pos)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;

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

			--_size;

			return iterator(next);
		}

		size_t size()
		{
			return _size;
		}
	private:
		Node* _head;
		size_t _size;
	};

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

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

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

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

		list<int> lt1(lt);
		for (auto e : lt1)
		{
			cout << e << " ";
		}
		cout << endl;

		list<int> lt2;
		lt2.push_back(10);
		lt2.push_back(20);
		lt2.push_back(30);
		lt2.push_back(40);
		lt2.push_back(50);

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

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

		int _a1;
		int _a2;
	};

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

		list<AA>::iterator it = lt.begin();
		while (it != lt.end())
		{
			cout << it->_a1 << " " << it->_a2 << endl;
			cout << it.operator->()->_a1 << " " << it.operator->()->_a2 << endl;
			++it;
		}
		cout << endl;
	}

	//template<typename T>
	//void print_list(const list<T>& lt)
	//{
	//	// list<T>是未实例化的类模板,编译器不能去他里面找
	//	// 编译器无法判断list<T>::const_iterator是内嵌类型,还是静态成员变量
	//	// 前面加一个typename就是告诉编译器,这是一个类型,等list<T>实例化
	//	// 再去类里面找
	//	typename list<T>::const_iterator it = lt.begin();
	//	while (it != lt.end())
	//	{
	//		cout << *it << " ";
	//		++it;
	//	}
	//	cout << endl;
	//}

	template<typename Container>
	void print_container(const Container& con)
	{
		typename Container::const_iterator it = con.begin();
		while (it != con.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

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

		vector<string> v;
		v.push_back("11111111111");
		v.push_back("11111111111");
		v.push_back("11111111111");
		v.push_back("11111111111");
		print_container(v);
	}
}

3、list与vector的对比

相关推荐
zhangpz_几秒前
c ++零基础可视化——vector
c++·算法
小灰灰__3 分钟前
Linux离线安装Docker命令,简单镜像操作
linux·docker·eureka
萨达大13 分钟前
23种设计模式-模板方法(Template Method)设计模式
java·c++·设计模式·软考·模板方法模式·软件设计师·行为型设计模式
刀鋒偏冷29 分钟前
ninja: error: ‘/opt/homebrew/Cellar/opensslxxx/xx/lib/libssl.dylib
c++
AI视觉网奇31 分钟前
pytorch3d linux安装
linux·人工智能·pytorch
双手插兜-装高手41 分钟前
Linux - 线程基础
linux·c语言·笔记
理论最高的吻1 小时前
98. 验证二叉搜索树【 力扣(LeetCode) 】
数据结构·c++·算法·leetcode·职场和发展·二叉树·c
沈小农学编程1 小时前
【LeetCode面试150】——202快乐数
c++·python·算法·leetcode·面试·职场和发展
XY.散人1 小时前
初识Linux · 信号处理
linux·信号处理
ZZZ_O^O1 小时前
【动态规划-卡特兰数——96.不同的二叉搜索树】
c++·学习·算法·leetcode·动态规划