C++ STL --- list的使用

目录

1.构造模块

  (1)无参构造函数

  (2)n个相同元素的构造函数

  (3)区间构造

  (4)C++11构造新形式

  (5)拷贝构造函数

  (6)赋值运算符重载 

2.迭代器模块

  (1)正向迭代器

  (2)反向迭代器

3.容量模块

  (1)判空函数

  (2)获取有效元素个数

  (3)设置有效元素个数

4.元素访问模块

  (1)获取首元素

  (2)获取尾元素

5.修改模块

  (1)头插

  (2)尾插

  (3)头删

  (4)尾删

  (5)任意位置插入

  (6)任意位置删除 

  (7)assign函数

  (9)清空

6.特殊操作模块

  (1)删除特定元素

  (2)排序

  (3)去重

  (4)逆置元素

  (5)指定条件的删除

7.迭代器失效 

  (1)迭代器失效原因       

    [1]删除操作

    [2]改变容量的操作

  (2)迭代器失效解决办法


        list是C++中带头结点的双向链表(也是模板),示意图如下。begin迭代器指向头结点正方向的第一个有效元素,end迭代器指向正方向最后一个有效元素的下一个位置,也就是头结点。 反向迭代器与之相反。

 

        跟其他容器一样,list也是主要讲解六大模块:构造模块、迭代器模块、容量模块、元素访问模块、修改模块、特殊操作模块。

        本文代码均在win10系统的vs2019中验证。

1.构造模块

函数说明功能说明
list()构造空的list
list(size_type n, const value_type & val = value_type())
构造的list中包含n个值为val的元素
list(const list& x)拷贝构造函数
 list(InputIterator first, InputIterator last)区间构造

  (1)无参构造函数

        注意:list也是模板,也需要在实例化时声明存储的元素的类型。使用时也需要加上list的头文件。

#include "list"
void Test() {
	list<int>L1;
}

  (2)n个相同元素的构造函数

#include "list"
void Test() {
	//用10个5构造
	list<int>L2(10,5);
}

  (3)区间构造

#include "list"
void Test() {
	int arr[] = { 1,2,3,4,5 };
	list<int>L3(arr,arr+sizeof(arr)/sizeof(arr[0]));
}

  (4)C++11构造新形式

        C++11中提供的新方式,可以在构造时直接传入数组。

#include "list"
void Test() {
	list<int>L4{ 1,2,3,4,5 };
}

  (5)拷贝构造函数

#include "list"
void Test() {
	list<int>L5(4, 9);
	list<int>L6(L5);
}

  (6)赋值运算符重载 

#include "list"
void Test() {
	list<int> L1{ 1,2,3 };
	list<int> L2 = L1;
}

2.迭代器模块

函数说明功能说明
begin() 正向迭代器,返回指向正向第一个有效元素的迭代器
end()正向迭代器,返回指向正向最后一个有效元素下一个元素的迭代器
rbegin()反向迭代器,返回指向反向第一个有效元素的迭代器
rend()反向迭代器,返回指向反向最后一个有效元素下一个元素的迭代器

示意图已经在开头给出。

  (1)正向迭代器

        注意,list的迭代器不可以+1,因为这是链表,不是一段连续的空间。 但可以使用++,因为++已经被重载过了。

#include "iostream"
using namespace std;
#include "list"
void Test() {
	list<int>L1{ 1,2,3,4,5 };
	auto it = L1.begin();
	while (it != L1.end()) {
		cout << *it;
		it++;
	}
}

  (2)反向迭代器

#include "iostream"
using namespace std;
#include "list"
void Test() {
	list<int>L2{ 1,2,3,4,5 };
	auto it = L2.rbegin();
	while (it != L2.rend()) {
		cout << *it;
		it++;
	}
}

3.容量模块

函数说明功能说明
empty()判断list是否是空,如果是,返回true
size()返回list中有效元素的个数
resize(size_t num, const T& value = T())将list的有效元素个数设置为num,如果num大于size(),多余的位置用value填充,没有给出value,就用T()填充。

  (1)判空函数

#include "iostream"
using namespace std;
#include "list"
void Test() {
	list<int>L1{ 1,2,3,4,5 };
	cout << L1.empty();
}

  (2)获取有效元素个数

#include "iostream"
using namespace std;
#include "list"
void Test() {
	list<int>L1{ 1,2,3,4,5 };
	cout << L1.size();
}

  (3)设置有效元素个数

#include "list"
void Test() {
	list<int>L1{ 1,2,3,4,5 };
	//将元素增加到10个多余空间用4填充
	L1.resize(10,4);
	//将元素缩减到4个
	L1.resize(4);
}

4.元素访问模块

函数说明功能说明
front()返回list中正方向第一个有效元素的引用
back()返回list中正方向最后一个有效元素的引用

  (1)获取首元素

#include "iostream"
using namespace std;
#include "list"
void Test() {
	list<int>L1{ 1,2,3,4,5 };
	//获取首元素
	cout << L1.front() << endl;
}

  (2)获取尾元素

#include "iostream"
using namespace std;
#include "list"
void Test() {
	list<int>L1{ 1,2,3,4,5 };
	//获取尾部元素
	cout << L1.back() << endl;
}

5.修改模块

函数说明功能说明
push_front(T& value)头插,在list第一个有效元素前插入一个value元素
push_back(T& value)尾插,在list最后一个有效元素后插入一个value元素
pop_front()头删,删除list中第一个有效元素
pop_back()尾删,删除list中最后一个有效元素
insert(iterator position, const value_type & val)
在迭代器position的位置插入一个val
insert(iterator position, size_type n, const value_type & val)在迭代器position的位置插入n个val
insert(iterator position, InputIterator first, InputIterator last)在迭代器position的位置插入一段区间。
void assign(InputIterator first, InputIterator last)用区间中的元素取代原本空间中的所有元素
void assign(size_type n, const value_type& val)用n个val元素取代原本空间中的所有元素
void clear()清空list的有效元素

  (1)头插


#include "list"
void Test() {
	list<int>L1{ 1 };
	//头插
	L1.push_front(2);
}

  (2)尾插

#include "list"
void Test() {
	list<int>L1{ 1 };
	//尾插
	L1.push_back(2);
}

  (3)头删

#include "list"
void Test() {
	list<int>L1{ 1,2};
	//头删
	L1.pop_front();
}

  (4)尾删

#include "list"
void Test() {
	list<int>L1{ 1,2};
	//尾删
	L1.pop_back();
}

  (5)任意位置插入

#include "iostream"
using namespace std;
#include "list"

void Test() {
	list<int>L1{ 1,2};
	//在某个迭代器的位置插入元素
	L1.insert(L1.begin(), 3);

	//在某个迭代器的位置插入3个4
	L1.insert(L1.begin(), 3, 4);

	//在某个迭代器的位置插入一个区间
	int arr[] = { 9,7,5,8,6 };
	L1.insert(L1.end(), arr, arr + sizeof(arr) / sizeof(arr[0]));
}

  (6)任意位置删除 

#include "iostream"
using namespace std;
#include "list"
void Test() {
	list<int>L1{ 1,2,3,4,5,6,7};
	//删除某个迭代器位置的元素
	L1.erase(L1.begin());
	//删除迭代器区间内的元素
	L1.erase(L1.begin(), L1.end());
}

  (7)assign函数

#include "iostream"
using namespace std;
#include "list"
void Test() {
	list<int>L1;
	//给L1中放入10个5
	L1.assign(10, 5);
	//给L1中放入一个区间
	//注意:每次使用时,会把原本的内容全部替换掉
	int arr[] = { 1,2,3,4 };
	L1.assign(arr, arr + sizeof(arr) / sizeof(arr[0]));
}

  (9)清空

#include "iostream"
using namespace std;
#include "list"

void Test() {
	list<int>L1{ 1,2,3,4,5 };
	L1.clear();
}

6.特殊操作模块

函数说明功能说明
remove(T& value)删除list中的全部value元素
sort()为list排序
unique()为list去除重复元素,但去重前必须先排序
reverse()逆置list中的元素
remove_if(函数名)定义一个函数用来筛选需要删除的元素,函数名作为参数传递给remove_if函数,就可以自定义删除元素了。

  (1)删除特定元素

#include "list"
void Test() {
	list<int>L1{1,2,6,1,2,4,6,7};
	//删除所有1
	L1.remove(1);
}

  (2)排序

#include "list"
void Test() {
	list<int>L1{1,2,6,1,2,4,6,7};
	//排序
	L1.sort();
}

  (3)去重

#include "list"
void Test() {
	list<int>L1{1,2,6,1,2,4,6,7};

	//排序
	L1.sort();
	//去重 去重之前必须排序
	L1.unique();
}

  (4)逆置元素

#include "list"
void Test() {
	list<int>L1{1,2,6,1,2,4,6,7};
	//逆置
	L1.reverse();
}

  (5)指定条件的删除

        需要自己给出一个函数来确定删除的元素需要满足的条件,然后把函数名作为参数传递给remove_if函数。

#include "list"
bool isEven(int data) {
	return data % 2 == 0;
}
void Test() {
	list<int>L1{1,2,6,1,2,4,6,7};
	//删除2的倍数
	L1.remove_if(isEven);
}

7.迭代器失效 

        跟vector一样,list也需要考虑迭代器失效的问题。但因为之前的文章已经讲过了,这里就简单给几个例子。

        迭代器本质:指针

        迭代器失效:指针指向的空间非法。即指针指向了被释放的空间。

  (1)迭代器失效原因       

        导致list迭代器失效的操作:

    [1]删除操作

        如:erase,pop_back,pop_front

        如下代码:        

        it首先指向元素1。头删后,元素1被删除,元素1所处的空间被释放,也就是it指向的空间被释放,但it仍旧指向它。

        在循环体中,试图对it进行解引用,但it此时已经是野指针,所以会报错。

#include "iostream"
#include "list"
using namespace std;

void Test() {
	list<int>L1{ 1,2,6,1,2,4,6,7 };
	//it此时指向元素1所在的空间
	auto it = L1.begin();
	//将元素1删除,释放元素1的空间,可是it仍旧指向那块空间
	L1.pop_front();
	while (it != L1.end()) {
		//试图对已经释放的空间的地址进行解引用
		cout << *it;
		it++;
	}
}

int main() {
	Test();
}

    [2]改变容量的操作

        如:resize assign

        it最初指向元素7的空间,但resize将有效元素个数缩减,只保留前三个元素,将其余元素空间释放。it指向了被释放的空间,成为野指针,试图解引用,就会报错。

#include "iostream"
#include "list"
using namespace std;

void Test() {
	list<int>L1{ 1,2,6,1,2,4,6,7 };
	//it首先指向元素7的空间
	auto it = L1.end();
	//改变list的有效元素个数,此时有效元素只有前三个
	//其余元素被删除,空间被释放,但此时it仍旧指向元素7的空间
	//也就是it指向被释放的空间
	L1.resize(3);
	//试图对被释放的空间地址进行解引用
	cout << *it << endl;
}

int main() {
	Test();
}

  (2)迭代器失效解决办法

        当进行了可能会导致之前使用的迭代器失效的操作后,如果还要使用迭代器,就在使用前对其进行重新赋值

void Test() {
	list<int>L1{ 1,2,6,1,2,4,6,7 };
	auto it = L1.begin();
	L1.pop_front();
	//使用前重新赋值
	it = L1.begin();
	while (it != L1.end()) {
		cout << *it;
		it++;
	}
}

void Test() {
	list<int>L1{ 1,2,6,1,2,4,6,7 };
	auto it = L1.end();
	L1.resize(3);
    //使用前重新赋值
	it = L1.end();
	cout << *it << endl;
}
  • 38
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 31
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值