C++ std::list 基本用法

#include <iostream>
#include <string>
#include <list>

using namespace std;

// https://zh.cppreference.com/w/cpp/container/list

/*
* std::list 是支持常数时间从容器任何位置插入和移除元素的容器。不支持快速随机访问。它通常实现为双向链表。
*
* 在 list 内或在数个 list 间添加、移除和移动元素不会非法化迭代器或引用。迭代器仅在对应元素被删除时非法化。
*
* T 必须满足可复制赋值 (CopyAssignable) 和可复制构造 (CopyConstructible) 的要求。
*/

std::ostream& operator<<(std::ostream& ostr, const std::list<int>& list)
{
	for (auto &i : list) {
		ostr << " " << i;
	}
	return ostr;
}

class item
{
public:
	item() = delete;
	item(const int& a, const int& b)
		: m_a(a), m_b(b)
	{}

	bool operator< (const item& comp) const
	{
		return m_a*m_b < comp.m_a*comp.m_b;
	}

	bool operator== (const item& comp) const
	{
		return m_a==comp.m_a && m_b==comp.m_b;
	}

private:
	int m_a;
	int m_b;
};

int main()
{
	int a[] = {1,2,3};
	list<int> l;
	list<int> l2({4,5,6});
	list<int> l3(a, a+3);
	//list<int> l4(l3); // deep copy
	list<int> l5 = l3; // deep copy
	list<int> l5_2 = { 1,2,3,4,5,6,7,8,9,0 };

	//////////////////////////////////////////////////////////////////////////

	l.push_back(1);
	l.push_back(2);

	l.push_front(-1);
	l.push_front(-2); // -2, -1, 1, 2

	l.pop_back();	// 去尾
	l.pop_front();	// 去头

	l.emplace_back(10);  // 比 push_back 少执行一次 copy ctor / 拷贝构造。当元素为自定义的类时,效率差异明显。
	l.emplace_front(-10);

	l.emplace(l.begin(), 5); // 比 insert 少执行一次 copy ctor / 拷贝构造。当元素为自定义的类时,效率差异明显。

	//////////////////////////////////////////////////////////////////////////

	// void assign(std::initializer_list<T> ilist);
	l.assign({});
	l.assign({11,12,13});

	// void assign( size_type count, const T& value );
	l.assign(5, 14); // 5个14

	// template< class InputIt >
	// void assign(InputIt first, InputIt last);
	l.assign(l3.begin(), l3.end());

	//////////////////////////////////////////////////////////////////////////

	// begin end
	for (auto it = l5.begin(); it != l5.end(); ++it)
	{
		cout << *it;
	}
	cout << endl; // 123

	// cbegin cend 常量,保证不改变 list 中的元素
	for (auto it = l5.cbegin(); it != l5.cend(); ++it)
	{
		cout << *it;
	}
	cout << endl; // 123

	// rbegin rend 注意偏移是 ++ 操作
	for (auto it = l5.rbegin(); it != l5.rend(); ++it)
	{
		cout << *it;
	}
	cout << endl; // 321

	//////////////////////////////////////////////////////////////////////////

	// iterator erase (const_iterator position);
	l5.erase(l5.begin()); // delete 1; size = 2

	// iterator erase (const_iterator first, const_iterator last);
	l5.erase(l5.begin(), l5.end()); // delete all

	list<int> l5_3({ 1,2,3,4,5,6,7,8,9,0 });
	auto it = l5_3.begin();
	it++; // 不支持 + ,没有 + 重载。但是可以使用 std::advance 函数来完成固定步长的迭代器移动。
	++it;
	l5_3.erase(l5_3.begin(), it); // delete 1 and 2

	list<int> l6({ 1,2,3,4,5,6,7,8,9,0 });
	auto it6 = l6.begin();
	std::advance(it6, 2);		// 使用 std::advance 函数来完成固定步长的迭代器移动。
	l6.erase(l6.begin(), it6);	// delete 1 and 2

	//////////////////////////////////////////////////////////////////////////

	// max_size; Returns the maximum number of elements that the vector can hold.
	// 系统或者库的设计上线。并非机器所能申请的最大大小。
	size_t maxSize = l5.max_size();

	bool isEmpty = l5.empty();

	size_t listSize = l5.size();

	//////////////////////////////////////////////////////////////////////////

	l5.clear();

	l5.swap(l);        // 两者交换
	///l5.swap(std::list<int>());       // 2015支持,2017不支持

	//////////////////////////////////////////////////////////////////////////
	list<int> l7({ 1,2,3,4,5,6,7,8,9,0 });

	// iterator insert( iterator pos, const T& value );
	l7.insert(l7.begin(), 101); // 101,1,2,3,4,5,6,7,8,9,0

	// void insert( iterator pos, size_type count, const T& value );
	l7.insert(l7.begin(), 2, 102); // 102,102,101,1,2,3,4,5,6,7,8,9,0

	// template< class InputIt >
	// void insert(iterator pos, InputIt first, InputIt last);
	list<int> l8({ 11,21,31,41,51,61,71,81 });
	l7.insert(l7.end(), l8.begin(), l8.end()); // 102,102,101,1,2,3,4,5,6,7,8,9,0,11,21,31,41,51,61,71,81

	// iterator insert( const_iterator pos, std::initializer_list<T> ilist );
	l7 = { 1,2,3,4,5,6,7,8,9,0 };
	l7.insert(l7.end(), { 11,21,31 }); // 1,2,3,4,5,6,7,8,9,0,11,21,31
	///l7.insert(l7.end(), l8); // 非法。此第二形参好像仅支持 {} 。
	///l7.insert(l7.end(), std::list<int>(l8)); // 非法。此第二形参好像仅支持 {} 。
	///l7.insert(l7.end(), std::list<int>(a, a+3)); // 非法。此第二形参好像仅支持 {} 。

	//////////////////////////////////////////////////////////////////////////

	//void resize( size_type count );
	l7.resize(2); // 1,2

	//void resize( size_type count, T value = T() );
	//void resize( size_type count, const value_type& value );
	l7.resize(4, 5); // 1,2,5,5

	//////////////////////////////////////////////////////////////////////////

	// 不复制或移动元素,仅重指向链表结点的内部指针。
	// 归并二个已排序链表为一个。链表应以升序排序

	// void merge( list& other );
	std::list<int> list1 = { 5,9,0,1,3 };
	std::list<int> list2 = { 8,7,2,6,4 };

	list1.sort(); // 默认升序
	list2.sort();
	std::cout << "list1:  " << list1 << "\n";
	std::cout << "list2:  " << list2 << "\n";
	list1.merge(list2); // 归并二个已排序链表为一个。链表应以升序排序。list2 会变成空!!!
	std::cout << "merged: " << list1 << "\n";

	// template <class Compare>
	// void merge(list& other, Compare comp);
	std::list<item> list1_item = { {1,1}, {7,7}, {2,2}, {0,0} };
	std::list<item> list2_item = { {2,2}, {4,4}, {3,3} };
	list1_item.sort(); // 默认升序,operator < 已经在 class item 中定义。
	list2_item.sort();
	list1_item.merge(list2_item, [&](item A, item B) { return A < B; }); // list2_item 会变成空!!!没有拷贝操作。

	//////////////////////////////////////////////////////////////////////////

	// 和 insert 相比,没有赋值操作。

	std::list<int> l9 = { 1, 2, 3, 4, 5 };
	std::list<int> ltt = { 10, 20, 30, 40, 50 };

	auto it9 = l9.begin();
	std::advance(it9, 2);
	// void splice( const_iterator pos, list&& other );
	l9.splice(it9, ltt); // 1, 2, 10, 20, 30, 40, 50, 3, 4, 5;执行结果与 insert 相同。ltt 变为空。insert 时 ltt不会清空。

	l9 = { 1, 2, 3, 4, 5 };
	it9 = l9.begin();
	ltt = { 10, 20, 30, 40, 50 };
	// void splice( const_iterator pos, list& other, const_iterator it );
	auto it_ltt = ltt.begin();
	std::advance(it_ltt, 2);
	l9.splice(it9, ltt, it_ltt); // 30, 1, 2, 3, 4, 5 // ltt 若为空,出错。// 只移动一个。

	l9 = { 1, 2, 3, 4, 5 };
	it9 = l9.begin();
	ltt = { 10, 20, 30, 40, 50 };
	// void splice( const_iterator pos, list& other, const_iterator first, const_iterator last);
	l9.splice(it9, ltt, ltt.begin(), ltt.end()); // 1, 2, 100, 200, 10, 20, 30, 40, 50, 3, 4, 5 // 移动一段。

	//////////////////////////////////////////////////////////////////////////
	l9.reverse(); // 反转

	std::list<int> l10 = { 1,100,2,3,10,1,11,-1,12 };

	l10.remove(1); // 移除两个等于 1 的元素
	l10.remove_if([](int n) { return n > 10; }); // 移除全部大于 10 的元素

	//////////////////////////////////////////////////////////////////////////

	// 从容器移除所有 相邻 的重复元素。只留下相等元素组中的第一个元素。

	std::list<int> l11 = { 1, 2, 2, 3, 3, 2, 1, 1, 2 };
	// void unique();
	l11.unique(); // 1 2 3 2 1 2

	std::list<item> l12 = { {1,1}, {7,7}, {7,7}, {2,2}, {0,0}, {2,2} };
	l12.unique(); // item 必须要重载 == // {1,1}, {7,7}, {2,2}, {0,0}, {2,2} // 自定义比较方法

	// template< class BinaryPredicate >
	// void unique(BinaryPredicate p); // 自定义比较方法
	l11 = { 1, 3, 3, 1, 2, 2, 1, 2, 2, 15 };
	l11.unique([](int a, int b) { return abs(b-a)<=1; }); // 1 3 1 15 // 自定义相等的条件。

	//////////////////////////////////////////////////////////////////////////
	l11.sort();						// 1 1 3 15 // 默认升序
	l12.sort();						// 默认升序,operator < 已经在 class item 中定义。
	l11.sort(std::greater<int>());	// 降序

}

  

原文地址:https://www.cnblogs.com/alexYuin/p/12044250.html

时间: 2024-10-15 03:24:46

C++ std::list 基本用法的相关文章

C++ std::map::erase用法及其陷阱

1.引入: STL的map中有一个erase方法用来从一个map中删除制定的节点 eg: map<string,string> mapTest; typedef map<string,string>::iterator ITER; ITER iter=mapTest.find(key); mapTest.erase(iter); 像上面这种删除单个节点,map的行为不会出现问题,但是当在一个循环里用的时候,往往会被误用. 2.陷阱 eg: for(ITER iter=mapTest

C++ std::pair的用法

1 pair的应用 pair是将2个数据组合成一个数据,当需要这样的需求时就可以使用pair,如stl中的map就是将key和value放在一起来保存.另一个应用是,当一个函数需要返回2个数据的时候,可以选择pair. pair的实现是一个结构体,主要的两个成员变量是first second 因为是使用struct不是class,所以可以直接使用pair的成员变量. 2 make_pair函数 template pair make_pair(T1 a, T2 b) { return pair(a

STL std::pair基本用法

std::pair 是一个结构体模板,其可于一个单元内存储两个相异对象.是 std::tuple 的拥有两个元素的特殊情况. 一般来说,pair 可以封装任意类型的对象,可以生成各种不同的 std::pair<T1, T2> 对象,可以是数组对象或者包含 std::pair<T1,T2> 的 vector 容器.pair 还可以封装两个序列容器或两个序列容器的指针. 1. 定义 #include <utility> template<class T1, class

C++ std::vector 基本用法2

#include <iostream> #include <vector> using namespace std; int main() { int ar[10] = { 1,2,3,4,5,6,7,8,9,0 }; std::vector<int> vec5(ar, ar + 10); // reverse size_t cap1 = vec5.capacity(); // = 10 vec5.reserve(20); // = Request a change i

C++ std::array 基本用法

#include <iostream> #include <string> #include <array> using namespace std; // https://zh.cppreference.com/w/cpp/container/array int main() { ///array<int, 3> arr({ 1,2,3 }); // 非法 array<int, 3> arr1{ { 1,2,3 } }; // 不可以扩容,属于

C++ std::forward_list 基本用法

#include <iostream> #include <string> #include <forward_list> using namespace std; // https://zh.cppreference.com/w/cpp/container/forward_list std::ostream& operator<<(std::ostream& ostr, const std::forward_list<int>&

C++ std::deque 基本用法

#include <iostream> #include <string> #include <deque> // https://zh.cppreference.com/w/cpp/container/deque // vector 和 deque 的差别 // https://www.cnblogs.com/zhuyf87/archive/2012/12/09/2809896.html using namespace std; int main() { int a[

std::back_inserter函数用法

back_inserter函数:配合copy函数,把[a, b)区间的数据插入到string对象的末尾,如果容量不够,动态扩容. 使用案例: 1.客户端与服务器通信场景:服务器向客户端发送数据,客户端接收数据. 接收数据的三种方法: (1)错误方法:把接收到的c风格字符串用string构造函数转成string对象,再利用string的重载加运算符函数拼接到变量末尾.数据很有可能是不以'\0'结尾,这样的话将出现严重bug. (2)低效率方法:一个字符一个字符的追加. (3)正确高效方法:运用co

c++ std::string 用法

std::string用法总结 在平常工作中经常用到了string类,本人记忆了不好用到了的时候经常要去查询.在网上摘抄一下总结一下,为以后的查询方便: string类的构造函数: string(const char *s);    //用c字符串s初始化string(int n,char c);     //用n个字符c初始化 string类的字符操作: const char &operator[](int n)const; const char &at(int n)const; cha