C++ list 的使用

目录

1. 构造函数

1.1 list ()

1.2 list (size_t n, const T& val = T())

1.3 list (InputIterator first, InputIterator last)

2. bool empty() const

3.  size_type size() const

4. T& front()

 4. T& back()

5. void push_front (const T& val)

6. void pop_front()

7. void push_back (const T& val)

8. void pop_back()

9. 迭代器

10. iterator insert (iterator pos, const T& val)

11.  void insert (iterator pos, size_t n, const T& val)

12. iterator erase (iterator pos)

13. void swap (list& x)

14. void resize (size_t n, const T& val = T())

15.  void clear()

16. 下面的这些函数都很好理解 

16.1 void remove (const T& val)

16.2 void unique()

16.2 void merge(list& x)

16.3 void sort()

16.4 void reverse()


list 的介绍,来源:list - C++ Reference (cplusplus.com)

1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。

2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向 其前一个元素和后一个元素。

3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高 效。

4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率 更好。

5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list 的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间 开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这 可能是一个重要的因素)

1. 构造函数

1.1 list ()

这里的 T 是模板参数,list 可以存储任意类型的数据嘛。

通过 list 的简介,我们知道 list 的底层其实是一个带头双向循环链表 (以下简称双链表),在定义 list 的时候,我们需要初始化一个哨兵位的头结点。哨兵位的头结点不存储有效数据。无参构造就是用来初始化哨兵位的头结点的!

1.2 list (size_t n, const T& val = T())

这个构造函数可以初始化一个长度为 n 的,值均为 val 的双链表。

#include<iostream>
#include<list>

using namespace std;

int main()
{
	list<int> lt(5, 8);
	//输出:8 8 8 8 8
	for (auto e : lt)
		cout << e << " ";
	cout << endl;
}

1.3 list (InputIterator first, InputIterator last)

这个构造函数可以用一段迭代器区间来初始化双链表。构造的区间:[first, last)。

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	vector<int> arr;
	arr.push_back(1);
	arr.push_back(2);
	arr.push_back(3);
	arr.push_back(4);
	arr.push_back(5);

	list<int> lt(arr.begin(), arr.end());
	//输出:1 2 3 4 5
	for (auto e : lt)
		cout << e << " ";
	cout << endl;

	return 0;
}

2. bool empty() const

判断一个链表是不是空链表!如果有有效数据,返回 true,反之返回 false。

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	list<int> lt1;
	cout << lt1.empty() << endl; //输出:1

	list<int> lt2(5, 8);
	cout << lt2.empty() << endl; //输出:0

	return 0;
}

3.  size_type size() const

这个函数可以获取双链表的长度。

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	list<int> lt2(5, 8);
	cout << lt2.size() << endl; //输出:5

	return 0;
}

4. T& front()

这个函数可以获取双链表的第一个有效元素。有 const 和非 const 两个版本,支持普通对象和 const 对象的调用。

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	vector<int> arr;
	arr.push_back(1);
	arr.push_back(2);
	arr.push_back(3);
	arr.push_back(4);
	arr.push_back(5);

	list<int> lt(arr.begin(), arr.end());

	cout << lt.front() << endl; //输出:1

	return 0;
}

 4. T& back()

这个函数可以获取双链表的最后一个有效元素。有 const 和非 const 两个版本,支持普通对象和 const 对象的调用。

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	vector<int> arr;
	arr.push_back(1);
	arr.push_back(2);
	arr.push_back(3);
	arr.push_back(4);
	arr.push_back(5);

	list<int> lt(arr.begin(), arr.end());

	cout << lt.back() << endl; //输出:5

	return 0;
}

5. void push_front (const T& val)

双链表头插元素。因为之前我们都用 C 语言实现过双链表,学习 list 的使用就非常简单啦!

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	list<int> lt;

	lt.push_front(4);
	lt.push_front(3);
	lt.push_front(2);
	lt.push_front(1);

	//输出:1 2 3 4
	for (auto e : lt)
		cout << e << " ";
	cout << endl;

	return 0;
}

6. void pop_front()

双链表头删元素。

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	list<int> lt;

	lt.push_front(4);
	lt.push_front(3);
	lt.push_front(2);
	lt.push_front(1);

	//输出:1 2 3 4
	for (auto e : lt)
		cout << e << " ";
	cout << endl;

    lt.pop_front();
    
	//输出:2 3 4
	for (auto e : lt)
		cout << e << " ";
	cout << endl;

	return 0;
}

7. void push_back (const T& val)

双链表尾插元素。

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	list<int> lt;

	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);

	//输出:1 2 3 4
	for (auto e : lt)
		cout << e << " ";
	cout << endl;

	return 0;
}

8. void pop_back()

双链表尾删元素。

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	list<int> lt;

	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);

	//输出:1 2 3 4
	for (auto e : lt)
		cout << e << " ";
	cout << endl;

    lt.pop_back();

	//输出:1 2 3
	for (auto e : lt)
		cout << e << " ";
	cout << endl;

	return 0;
}

9. 迭代器

list 的迭代器就不是简单的原生指针了。因为他的物理空间并不连续,因此 list 的迭代器需要进行封装,使得迭代器解引用能够返回节点存储的数据,使得迭代器加加,指向下一个节点,等等。具体的操作到我们模拟实现 list 的时候再说。

下面的图是 list 迭代器 begin() 与 end() 迭代器对应的双链表节点。

10. iterator insert (iterator pos, const T& val)

这个函数可以在 list 的 pos 位置处,插入一个值为 val 的元素。返回值就是返回新插入的元素的位置对应的迭代器。

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	list<int> lt;

	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);

	//在begin() 的位置插入 0 ,相当于头插
	lt.insert(lt.begin(), 0);

	//输出:0 1 2 3 4
	for (auto e : lt)
		cout << e << " ";
	cout << endl;

	//在end() 的位置插入 5 ,相当于尾插
	auto it = lt.insert(lt.end(), 5);

	cout << *it << endl; //输出:5


	//输出:0 1 2 3 4 5
	for (auto e : lt)
		cout << e << " ";
	cout << endl;


	return 0;
}

11.  void insert (iterator pos, size_t n, const T& val)

这个函数可以在 pos 位置插入 n 个值为 val 的节点。

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	list<int> lt;

	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);

	//在begin() 的 位置插入 3 个值为 0 的节点
	lt.insert(lt.begin(), 3, 0);

	//输出:0 0 0 1 2 3 4
	for (auto e : lt)
		cout << e << " ";
	cout << endl;

	return 0;
}

12. iterator erase (iterator pos)

这个函数可以删除 pos 位置的双链表节点。不可以删除 end() 位置的节点,会报错的!VS2022 做了检查的。

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	list<int> lt;

	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);

	//相当于头删
	lt.erase(lt.begin());

	//输出:2 3 4
	for (auto e : lt)
		cout << e << " ";
	cout << endl;

	return 0;
}

13. void swap (list<T>& x)

这个函数可以交换两个链表。我们实现 list 的时候,list 类中维护的是哨兵位的头结点的指针,交换两个链表的指针就能实现这样的效果。仅限于我们自己实现的 list 类哈!list 实现方式多种多样!

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	list<int> lt1;
	lt1.push_back(1);
	lt1.push_back(2);
	lt1.push_back(3);
	lt1.push_back(4);

	list<int> lt2;
	lt2.push_back(5);
	lt2.push_back(6);
	lt2.push_back(7);
	lt2.push_back(8);

	lt1.swap(lt2);

	//输出:5 6 7 8
	for (auto e : lt1)
		cout << e << " ";
	cout << endl;

	//输出:1 2 3 4
	for (auto e : lt2)
		cout << e << " ";
	cout << endl;


	return 0;
}

14. void resize (size_t n, const T& val = T())

stl 库的接口风格都很相似,list 的resize 和 vector,string 的 resize 简直一毛一样。当 n 小于双链表的长度,直接截断,当 n 大于双链表的长度,会用 val 区初始化新插入的节点。

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	list<int> lt;

	lt.push_back(0);
	
	lt.resize(5, 1);

	//输出: 0 1 1 1 1
	for (auto e : lt)
		cout << e << " ";
	cout << endl;


	return 0;
}

15.  void clear()

清空链表,即释放所有链表节点。

#include<iostream>
#include<list>
#include<vector>
using namespace std;

int main()
{
	list<int> lt;

	lt.push_back(0);
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);

	lt.clear();

    //没有输出
	for (auto e : lt)
		cout << e << " ";
	cout << endl;


	return 0;
}

16. 下面的这些函数都很好理解 

16.1 void remove (const T& val)

移除链表中所有值为 val 的节点。

1 2 3 3 4 5 remove(3) :1 2 4 5。

16.2 void unique()

删除链表中重复的节点。

1 2 2 3 3 4 5 1 remove(3) :1 2 3 4 5 1。

这个函数只能对相邻的重复的数去重。因此多用于已经排好序的 list。

16.2 void merge(list<T>& x)

这个函数用于两个 list 的合并,前提是两个 list 都被排好序了!

例如:

list1:-1 2 3 5 8

list2:0 1 2 4 6 7

合并后的结果:-1 0 1 2 2 3 4 5 6 7 8。

16.3 void sort()

链表的排序。

16.4 void reverse()

链表的逆置。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姬如祎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值