15.list(上)

无参构造,n个value 构造,迭代区间构造,拷贝构造

迭代器都一样,不一样的是链表还支持下标加方括号吗 ,不支持,获取下标能想办法,【】要从头开始获取第三个第五个,代价太大O(N)。之前数组都是o(1).

也能用范围for 其他迭代器就不演示了。

删除第三个位置数据不能这么写迭代器不是原生指针,找第几个很麻烦,之前说从功能上划分iterator reverse------iterator const------iterator const------reverse------iterator ,

决定迭代器性质的是由底层结构决定的。mebertype能看

sort只能用随机迭代器,不是就报错,底层是快排,三数取中要支持加减随机访问的,两个迭代器相加相减, 快排递归深度太深转换成别的堆排也要求随机访问,所以要随机迭代器,

reverse 要求传双向迭代器, forwardlist就不能用它逆置

因为这个算法用了--,vector string这些随机迭代器能不能用逆置啊,可以,双向是一种特殊单项,随机是特殊单项 双向,

find 这里的迭代器是input迭代器,这个迭代器,可以给任意类型迭代器,find只用了++,所以单项双向随机都可以,

看一个算法,看看容器到底支不支持,forward iterator 单项迭代器就行。

#include<algorithm>

给一个不匹配的迭代器实际编译会报错,实际底层用迭代器进行减,随机迭代器才进行+ -,

命名时候名字就暗示了要用哪些迭代器。

pushback支持的emplace也支持

如果插入的数据不是单个,emplace会有差别,

cpp 复制代码
struct A
{
public:
	A(int a1 = 1, int a2 = 1)
		:_a1(a1)
		,_a2(a2)
	{
		cout << "A(int a1 = 1, int a2 = 1)" << endl;
	}

	A(const A& aa)
		:_a1(aa._a1)
		,_a2(aa._a2)
	{
		cout << "A(const A& aa)" << endl;
	}

	int _a1;
	int _a2;
};

void test_list2()
{
	/*list<int> lt;
	lt.push_back(1);
	lt.emplace_back(2);
	lt.emplace_back(3);
	lt.emplace_back(4);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;*/

	list<A> lt;
	A aa1(1, 1);
	lt.push_back(aa1);
	lt.push_back(A(2,2));
	//lt.push_back(3, 3);

	lt.emplace_back(aa1);
	lt.emplace_back(A(2,2));
	cout << endl;
	// 支持直接传构造A对象的参数emplace_back
	lt.emplace_back(3, 3);
}

pushback支持的我也支持,我还可以3,3,因为pushcack只支持一个参数,,emplace是个模板的,可以自动推推导,底层比较复杂,上面的是把A构造好了,再去拷贝构造,

下面这个更高效一点,他把参数直接往下面传,到节点那一层直接构造就可以了,直接拿参数往下走,直接构造。

最后那个少一次拷贝构造,emplace效率高,

插入一个值,插入n个值,插入迭代器区间。如果想在第三个位置插入一下,不好搞。,迭代器限制,双向迭代器不能+3

erase支持删除一段迭代区间值,少,主要用删除某个位置的值

swap为了高效,不走深拷贝,交换指针就行。。。。这些都差不多

erase还是O(1),find是O(N)

双向链表插入,找到前一个就行,删除也是,O(1)

find是算法不是链表,甩锅嫌疑

这样可以逆置,但是

这也可以逆置,所以这些有些冗余,双向迭代器也支持

自己单独支持一个sort,因为双向链表的原因算法库不支持,算法库不支持,所以自己写了个

算法和这都是默认升序,这只管用。降序用到仿函数,这是个特殊的类

算法库有两个东西,<就是升序>就是降序

这就可以降序了。这时候传匿名对象就爽死了,有名对象还要写两行

算法库里sort也是默认升序,如果想降序,第三个传greater的匿名对象就行,

链表合并前提是要求链表有序

合并时候就是取小的尾插,这是second合并给给first,second就空了,用得不多

unique去重,要求数据必须有序

后面5没去掉。因为他以为所有相同值都挨在一起,逻辑就是假设有序。

算法有序了以后想去重是很简单的事,遇到这个位置,用一个双指针,如果后一个值跟这个值相同,让后一个迭代器++,直到不相等,中间有值要把这段区间删掉,迭代器++,到这个位置,然后erase掉这个区间,就是双指针 如果有多个相同的,那就找到这个区间,然后第一个保留剩下erase,费劲的是sort,不排序去重,效率极低

remove就是删除一个值

splice:剪切

第二个是转移那一个,第三个转移区间

x插入position之前,我的链表就没了

拿走插入2之前,mylist2就空了

假设要把顺序转移一下,6转移到头上去

第一种方式5删除,头插入;第二种方式:直接诶转移走。splice 可以自己转移给自己

给it和it后面的值,如果给it,就把这一个值转移到前面了

splice可以把一个链表给另一个链表也可以调整一个链表的数据

cpp 复制代码
void test_list6()
{
	// 一个链表节点转移给另一个链表
	std::list<int> mylist1, mylist2;
	std::list<int>::iterator it;

	// set some initial values:
	for (int i = 1; i <= 4; ++i)
		mylist1.push_back(i);      // mylist1: 1 2 3 4

	for (int i = 1; i <= 3; ++i)
		mylist2.push_back(i * 10);   // mylist2: 10 20 30

	it = mylist1.begin();
	++it;                         // points to 2

	mylist1.splice(it, mylist2); // mylist1: 1 10 20 30 2 3 4
								  // mylist2 (empty)
								  // "it" still points to 2 (the 5th element


	// 调整当前链表节点的顺序
	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);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	int x = 0;
	cin >> x;
	it = find(lt.begin(), lt.end(), x);
	if (it != lt.end())
	{
		//lt.splice(lt.begin(), lt, it);
		lt.splice(lt.begin(), lt, it, lt.end());
	}

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

swap也是,不是调用库里的,头结点交换,效率最高

数据量少可以用链表排序,数据量不能用,效率低

cpp 复制代码
void test_op1()
{
	srand(time(0));
	const int N = 1000000;

	list<int> lt1;
	vector<int> v;

	for (int i = 0; i < N; ++i)
	{
		auto e = rand() + i;
		lt1.push_back(e);
		v.push_back(e);
	}

	int begin1 = clock();
	// 排序
	sort(v.begin(), v.end());
	int end1 = clock();

	int begin2 = clock();
	lt1.sort();
	int end2 = clock();

	printf("vector sort:%d\n", end1 - begin1);
	printf("list sort:%d\n", end2 - begin2);
}

测性能时候开release;因为debug优化没开全。

vector底层用的快排,递归在debug下面表现不好,因为debug要打很多调试信息,建立战阵存很多信息,调用很多函数,打印很多调试信息所以递归在debug下很差。但是火力全开就很牛bi。

cpp 复制代码
void test_op2()
{
	srand(time(0));
	const int N = 1000000;

	list<int> lt1;
	list<int> lt2;

	for (int i = 0; i < N; ++i)
	{
		auto e = rand()+i;
		lt1.push_back(e);
		lt2.push_back(e);
	}

	int begin1 = clock();
	// 拷贝vector
	vector<int> v(lt2.begin(), lt2.end());

	// 排序
	sort(v.begin(), v.end());

	// 拷贝回lt2
	lt2.assign(v.begin(), v.end());

	int end1 = clock();

	int begin2 = clock();
	lt1.sort();
	int end2 = clock();

	printf("list copy vector sort copy list sort:%d\n", end1 - begin1);
	printf("list sort:%d\n", end2 - begin2);
}

两个链表排序,用相同数据,

这时候用不了赋值因为一个是vector 一个是list,这里用assign

有个迭代区间,别人迭代区间也行,链表拷贝给vector ,vector排完序,在assign给链表,这样还是快。

相关推荐
zmzb01037 分钟前
C++课后习题训练记录Day50
开发语言·c++
LYFlied11 分钟前
【每日算法】LeetCode142. 环形链表 II
数据结构·算法·leetcode·链表
LYFlied13 分钟前
【每日算法】LeetCode 23. 合并 K 个升序链表
前端·数据结构·算法·leetcode·链表
HalvmånEver20 分钟前
Linux:基础IO(终)
linux·运维·c++·学习·缓冲区·libc
Fine姐21 分钟前
数据结构05——平衡二叉树
数据结构
laocooon52385788623 分钟前
背包问题~~!C++
开发语言·c++·算法
hweiyu0034 分钟前
数据结构:矩阵
数据结构·线性代数·矩阵
旺仔小拳头..37 分钟前
数据结构(一)———线性表之顺序表、单向链表
数据结构·算法
xiaoxue..40 分钟前
哨兵节点与快慢指针解决链表算法难题
前端·javascript·数据结构·算法·链表
矢鱼1 小时前
python中对应c++容器的结构
开发语言·c++·python·算法