List的理解和简单实现

目录

1. list的介绍及使用

2. list的介绍

3. list的使用

3.1. constructor的使用

3.2. 数据修改接口的使用

3.3. splice的使用: 

3.3.1. void splice (iterator position, list& x)

3.3.2.void splice (iterator position, list& x, iterator i)

3.3.3. void splice (iterator position, list& x, iterator first, iterator last)

3.4. remove的使用

3.5. std::list::sort


1. list的介绍及使用

// std::list
template < class T, class Alloc = allocator<T> > class list;

2. list的介绍

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

3. list的使用

3.1. constructor的使用

void Test1(void)
{
	//使用标准库中list的constructor

	//default
	std::list<int> lt1;
	//fill
	std::list<int> lt2(10, 1);
	//range
	std::vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	std::list<int> lt3(v.begin(), v.end());
	//copy
	std::list<int> lt4(lt3);

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

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

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

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

现象如下:

3.2. 数据修改接口的使用

void Test2(void)
{
	//关于Modifiers的接口的使用
	std::list<int> lt;
	//1.支持头插尾插
	lt.push_front(3);
	lt.push_front(2);
	lt.push_front(1);
	lt.push_back(2);
	lt.push_back(1);
	
	//2.支持任意位置插入
	//同样list没有提供find,统一用算法库#include <algorithm>里面的find
	std::list<int>::iterator pos1 = find(lt.begin(), lt.end(), 3);
	if (pos1 != lt.end())
	{
		lt.insert(pos1, 100);
	}
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	//3. 支持头删尾删
	lt.pop_front();
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	lt.pop_back();
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	//4.支持任意位置删除

	std::list<int>::iterator pos2 = std::find(lt.begin(), lt.end(), 100);
	if (pos2 != lt.end())
	{
		pos2 = lt.erase(pos2);
		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}

现象如下: 

3.3. splice的使用: 

splice()的功能就是将一个list的数据转移到另一个list上; 

//entire list (1)	
//转移所有数据
void splice (iterator position, list& x);

//single element (2)	
//仅仅转移i这个位置的数据
void splice (iterator position, list& x, iterator i);

//element range (3)	
//转移一段区间
void splice (iterator position, list& x, iterator first, iterator last);

3.3.1. void splice (iterator position, list& x)

void Test3(void)
{
	std::list<int> dst_lt;
	dst_lt.push_back(1);
	dst_lt.push_back(2);
	dst_lt.push_back(3);
	dst_lt.push_back(4);
	dst_lt.push_back(5);
	cout << "old dst_lt: " << endl;
	for (auto e : dst_lt)
	{
		cout << e << " ";
	}
	cout << endl;
	std::list<int> sur_lt;
	sur_lt.push_back(6);
	sur_lt.push_back(7);
	sur_lt.push_back(8);
	sur_lt.push_back(9);
	sur_lt.push_back(10);
	cout << "old sur_lt: " << endl;
	for (auto e : sur_lt)
	{
		cout << e << " ";
	}
	cout << endl;
	std::list<int>::iterator pos1 = dst_lt.begin();
	pos1++;
    //转移所有数据
	dst_lt.splice(pos1, sur_lt);
	cout << "new dst_lt: " << endl;
	for (auto e : dst_lt)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << "new sur_lt: " << endl;
	for (auto e : sur_lt)
	{
		cout << e << " ";
	}
	cout << endl;
}

现象如下:

3.3.2.void splice (iterator position, list& x, iterator i)

void Test3(void)
{
	std::list<int> dst_lt;
	dst_lt.push_back(1);
	dst_lt.push_back(2);
	dst_lt.push_back(3);
	dst_lt.push_back(4);
	dst_lt.push_back(5);
	cout << "old dst_lt: " << endl;
	for (auto e : dst_lt)
	{
		cout << e << " ";
	}
	cout << endl;
	std::list<int> sur_lt;
	sur_lt.push_back(6);
	sur_lt.push_back(7);
	sur_lt.push_back(8);
	sur_lt.push_back(9);
	sur_lt.push_back(10);
	cout << "old sur_lt: " << endl;
	for (auto e : sur_lt)
	{
		cout << e << " ";
	}
	cout << endl;
	std::list<int>::iterator pos1 = dst_lt.begin();
	pos1++;
	std::list<int>::iterator pos2 = std::find(sur_lt.begin(), sur_lt.end(), 8);
	dst_lt.splice(pos1, sur_lt,pos2);
	cout << "new dst_lt: " << endl;
	for (auto e : dst_lt)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << "new sur_lt: " << endl;
	for (auto e : sur_lt)
	{
		cout << e << " ";
	}
	cout << endl;
}

结果如下:

3.3.3. void splice (iterator position, list& x, iterator first, iterator last)

void Test3(void)
{
	std::list<int> dst_lt;
	dst_lt.push_back(1);
	dst_lt.push_back(2);
	dst_lt.push_back(3);
	dst_lt.push_back(4);
	dst_lt.push_back(5);
	cout << "old dst_lt: " << endl;
	for (auto e : dst_lt)
	{
		cout << e << " ";
	}
	cout << endl;
	std::list<int> sur_lt;
	sur_lt.push_back(6);
	sur_lt.push_back(7);
	sur_lt.push_back(8);
	sur_lt.push_back(9);
	sur_lt.push_back(10);
	cout << "old sur_lt: " << endl;
	for (auto e : sur_lt)
	{
		cout << e << " ";
	}
	cout << endl;
	std::list<int>::iterator pos1 = dst_lt.begin();
	pos1++;
	std::list<int>::iterator pos2 = std::find(sur_lt.begin(), sur_lt.end(), 7);
	std::list<int>::iterator pos3 = std::find(sur_lt.begin(), sur_lt.end(), 9);
    //转移一段区间
	dst_lt.splice(pos1, sur_lt,pos2,pos3);
	cout << "new dst_lt: " << endl;
	for (auto e : dst_lt)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << "new sur_lt: " << endl;
	for (auto e : sur_lt)
	{
		cout << e << " ";
	}
	cout << endl;
}

结果如下:

3.4. remove的使用

//Removes from the container all the elements that compare equal to val.

void remove (const value_type& val);

这里的remove是删除list<T>中的一个等于val的数据还是删除list<T>中所有等于val的数据呢?验证如下:

void Test4(void)
{
	std::list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(5);
	for (auto e : lt)
		cout << e << " ";
	cout << endl;
    // 删除3
	lt.remove(3);
	for (auto e : lt)
		cout << e << " ";
	cout << endl;
}

结果如下:

从结果来看,remove会删除list<T>中所有等于val的数据。

3.5. std::list::sort

我们知道,算法库里面也是有sort的(以快排的方式实现),为什么list要自己实现一个sort(以归并方式实现)呢?

答案是list不能使用标准算法库里面的sort,因为算法库里面的sort需要物理存储空间是连续的,而list的存储空间可不是连续的,如果使用标准库中的 std::sort,就会报错,如下:

因此, list 自己有一个成员函数 sort, 如下: 

void Test5(void)
{
	std::list<int> lt;
	lt.push_back(1);
	lt.push_back(3);
	lt.push_back(2);
	lt.push_back(5);
	lt.push_back(4);
	lt.sort();
	for (auto e : lt)
		cout << e << " ";
	cout << endl;
}

结果如下:

对比下std::sort和list::sort的效率: 

void Test6(void)
{
	srand(time(0));
	const int N = 10000000;
	std::vector<int> v;
	v.reserve(N);
	std::list<int> lt;
	for (size_t i = 0; i < N; ++i)
	{
		auto e = rand();
		v.push_back(e);
		lt.push_back(e);
	}
	int begin1 = clock();
	std::sort(v.begin(), v.end());
	int end1 = clock();

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

	cout << "std::sort  :" << end1 - begin1 << endl;
	cout << "list::sort :" << end2 - begin2 << endl;
}

在release版的结果如下:

有时候当数据量很大的时候,我们直接用list::sort还不如先把数据拷贝到vector里面进行排序,然后再拷回去,如下:

void Test6(void)
{
	srand(time(0));
	const int N = 10000000;
	std::vector<int> v;
	v.reserve(N);
	std::list<int> lt1;
	std::list<int> lt2;
	for (size_t i = 0; i < N; ++i)
	{
		auto e = rand();
		lt1.push_back(e);
		lt2.push_back(e);
	}
	int begin1 = clock();
	//1. 将数据插入到vector里
	for (auto e : lt1)
	{
		v.push_back(e);
	}
	//2. 让vector调用std::sort进行排序
	std::sort(v.begin(), v.end());
	size_t i = 0;
	//3. 将数据拷回list
	for (auto& e : lt1)
	{
		e = v[i++];
	}
	int end1 = clock();

	int begin2 = clock();
	// 让list直接排序
	lt2.sort();
	int end2 = clock();

	cout << "copy vector sort  :" << end1 - begin1 << endl;
	cout << "list::sort  :" << end2 - begin2 << endl;
}

relese版下结果如下:

可以看出,链表自身提供的排序效率有点低。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值