C++ STL容器 —— list 用法详解

C++ STL容器 —— list 用法详解

写在前面:近期正在学习C++的STL容器,因此在这里做一下日志记录,主要介绍一些容器基本成员函数的用法, 配上实际用例,并不涉及原理。但别人的博客终究是别人的, 最好自己上手操作一下.
写的不好, 请大神手下留情.

下面说的 “运行之后” 表示: 运行上个语句之后的结果.
一行如果说的太长的话, 就得拖动下面的进度条才能看到后面的内容, 非常麻烦
因此将一段话分成了多行,就像现在这种形式

简介

头文件: # include < list >
动态双向链表,用法和vector等容器基本相同, 但是内部结构区别很大
点击前往: vector 用法详解

构造函数

list <int> l, l1;
//定义 int 类型的链表

list <char> lch;
//定义 char 类型的链表

list <string> lstr;
//定义 string 类型的链表

list <int> l2(10);
//定义拥有 10 个元素的链表, 每个元素默认为 0

list <int> l3(5, 30);
//定义拥有 5 个元素的链表,并全部初始化为 30

list <int> l4{ 1,2,3,4 };
//定义拥有 4 个元素为{1,2,3,4}的链表, 

list <int> l5 = { 1,2,3,4 };
//同上

list <int> l6(l);
//定义新容器, 拷贝 l 所有的元素

list <int> l7(l.begin(), l.end());
//定义新容器, 拷贝 l 区间内所有的元素

访问/赋值

迭代器

分为:begin、end、rbegin、rend、cbegin、cend、crbegin、crend
使用方法:

auto it=l.begin(); //相当于指针,用 *it 访问

l.begin(); 返回迭代器, 指向第一元素
l.end(); 返回迭代器, 指向最末元素的下一个位置
l.cbegin(); 返回迭代器, 指向第一元素, 类型为const
l.rbegin(); 返回反向迭代器, 指向反向迭代的第一元素
l.rend(); 返回反向迭代器, 指向反向迭代的最末元素的下一个位置
l.crbegin(); 返回反向迭代器, 指向反向迭代的第一元素, 类型为const

例: 使用正向遍历 l 数组

list <int> l{ 1,2,3,4,5,6 };
for (auto it = l.begin(); it != l.end(); it++) {
	//注意这里是不等于end, 而不是小于end
	cout << *it <<' ';
}
输出结果为: 
1 2 3 4 5 6

例: 反向遍历 l 数组

list <int> l{ 1,2,3,4,5,6 };
for(auto it=l.rbegin();it!=l.rend();it++){
	//注意这里还是it++, 而不是it--
	cout << *it <<' ';
}
输出结果为: 
6 5 4 3 2 1

begin和rbegin的区别
l.begin()返回迭代器,指向容器内的第一元素
l.rbegin()返回逆序迭代器,指向容器内的最末元素
begin和cbegin的区别
可以通过l.begin()修改容器内元素的值
不能通过l.cbegin()修改容器内元素的值

下标 / at

不支持下标 [] 和 at 函数随机访问容器内元素,只能通过迭代器访问

assign (赋值函数)
l.assign(2, 3);
//将 2 个 3 赋值给 l
//例:l={5,6,7}
//运行之后 l={3,3,3}

l.assign(l1.begin(), l1.end());
//将区间内的元素赋值给 l
//例:l={5,6,7}, l1={1,2,3,4}
//运行之后 l={1,2,3,4}
swap (交换函数)
l.swap(l1);
//交换两个容器的内容
//例:l={1,2,3,4}, l1={5,6,7}
//运行之后, l={5,6,7}, l1={1,2,3,4}

常用函数

l.push_front(4);
//在头部插入元素 4
//例:l={1,2,3}
//运行之后, l={4,1,2,3}

l.push_back(4);
//在末端插入元素 3
//例:l={1,2,3}
//运行之后, l={1,2,3,4}

l.pop_front();
//删除第一元素
//例:l={1,2,3,4}
//运行之后, l={2,3,4}

l.pop_back();
//删除最末元素
//例:l={1,2,3,4}
//运行之后, l={1,2,3}

l.front();
//返回第一元素
//例:l={1,2,3,4}
//l.front()就等于 1

l.back();
//返回最末元素
//例:l={1,2,3,4}
//l.back()就等于 4

l.clear();
//清空容器

l.empty();
//容器为空返回 true, 否则返回 false

长度 / 空间 / 容量相关函数

l.size();
//返回容器目前的元素个数
//例: l={1,2,3}
//返回 3

l.max_size();
//返回元素个数 size 的最大值

l.resize(3);
//设置 l 的 size,影响 size
//设置之后 size=3
//例:l={1,2,3,4,5,6}
//运行之后 l={1,2,3}, 如果尺寸变小,多余的部分截掉
//例:l={1,2}
//运行之后 l={1,2,0}, 如果尺寸变大,新空间用 0 代替

l.resize(3, 2);
//设置 l 的 size,如果尺寸变大,新空间全部用 2 代替
//例: l={1,1}
//运行之后 l={1,1,2}

添加元素

insert (插入函数)
l.insert(l.begin(), 3);
//在位置之前插入元素 3
//例: l={1,2}
//运行之后 l={3,1,2}

l.insert(l.begin(), 2, 3);
//在位置之前插入 2 个元素 3
//例: l={1,2}
//运行之后 l={3,3,1,2}

l.insert(l.begin(), l1.begin(), l1.end());
//在位置之前插入l1 区间内所有的元素
//例: l={1,2}, l1={5,6,7},
//运行之后 l={5,6,7,1,2}
emplace系列 (插入函数)
l.emplace(l.begin(), 3);
//在位置之前插入元素 3, 相当于l.insert(l.begin(),3);
//例: l={1,2,4}
//运行之后 l={3,1,2,4}

l.emplace_front(3);
//在头部插入元素 3, 相当于l.push_front(3);
//例: l={1,2}
//运行之后 l={3,1,2}

l.emplace_back(3);
//在末端插入元素 3, 相当于l.push_back(3);
//例: l={1,2}
//运行之后 l={1,2,3}

emplace系列 / push系列 / insert的区别

  1. 原理上
    emplace系列 是直接将在位置上构造插入的内容, 不需要生成对象
    push系列 / insert是先生成具有复制内容的对象, 然后将对象的内容复制到容器里面
  2. 功能上
    emplace系列 / push系列 只能插入一个元素
    insert 可以插入多个
  3. 性能上
    因为功能比较少, 所以 emplace系列 的速度要更快一点

push系列与insert的区别

  1. 功能上
    push系列只能在头部或末端添加元素
    insert可以在任何地方添加元素
  2. 性能上
    push系列速度更快一点
merge (合并函数)
l.merge(l1);
//将 l1 的全部元素转移到 l 
//保证转移之前的 l / l1 有序, 转移后的 l 同样有序, 默认升序
//例: l={1,3,5}, l1={2,4,6}
//执行之后, l={1,2,3,4,5,6}, l1={};

l.merge(l1, greater <int>());
//将 l1 的全部元素转移到 l, 排序准则为降序
//例: l={5,3,1}, l1={6,4,2}
//执行之后, l={6,5,4,3,2,1}, l1={};

l.merge(l1, op);
// 将 l1 的全部元素转移到 l, 排序准则为 op
splice (拼接函数)
l.splice(l.begin(), l1);
//将 l1 转移到 l 的位置之前
//例: l={1,2}, l1={5,6,7},
//运行之后 l={5,6,7,1,2}, l1={};

l.splice(l.begin(), l1, l1.begin());
//将 l1 所指元素转移到 l 的位置之前: l={1,3,5}, l1={2,4,6}
执行之后, l={2,1,3,5}, l1={4,6};

l.splice(l.begin(), l1, l1.begin(), l1.end());
//将 l1 区间内元素转移到 l 的位置之前
//例: l={1,2}, l1={5,6,7},
//运行之后 l={5,6,7,1,2}, l1={};

insert / merge / splice 三个插入函数的区别
a.函数名(b)
将容器 b 的内容插入到容器 a 中

insert 函数就是正常的将容器 b 的内容复制插入到容器 a 中
merge 函数在使用之前两个容器必须具有相同的顺序(升序/降序/自定义的顺序), 是将容器 b 的内容按照一定的顺序移动插入到容器 a 中, 会将容器 b 中插入的内容删除
splice 函数是将容器 b 的内容移动插入到容器 a 中, 会将容器 b 中插入的内容删除

删除元素

erase (删除函数)
l.erase(l.begin());
//删除位置上的元素, 返回迭代器, 指向下一个元素
//例: l={1,2,3}
//运行之后 l={2,3}

l.erase(l.begin(), l.end());
//删除区间内的元素
//例: l={1,2,3}
//运行之后 l={}
remove系列 (移除函数)
l.remove(3);//删除所有值为 3 的元素
//例: l={1,2,3,3,4,3,3}
//运行之后 l={1,2,4}

l.remove_if(op);
//删除使 op() 为true的元素
bool op(int a) {
// 10~100 返回 false, 其余返回 true(删除不在10~100内的数)
	return a < 10 || a>100;
}
//例: l={1,2,10,50,60,100,111}
//运行之后 l={10,50,60,100}
unique (排重函数)
l.unique();
//删除相邻的相同元素, 只留一个
//例: l={1,2,3,3,3,4,5,5,6,3,3}
//运行之后 l={1,2,3,4,5,6,3}

erase / remove / unique 三个删除函数的区别
erase 函数是通过迭代器查找到元素之后, 进行删除
remove 函数是通过 值 查到元素之后, 进行删除
unique 函数只将相邻的相同元素删除, 没有真正达到排重的效果

更改数据

reverse (翻转函数)
l.reverse();
//翻转容器
//例:l={1,2,3,4}
//运行之后, l={4,3,2,1}
sort (排序函数)
l.sort();
//升序排序
//例: l={1,2,3,5,4,1,3}
//运行之后 l={1,1,2,3,3,4,5}

l.sort(greater<int>());
//降序排序
//例: l={1,2,3,5,4,1,3}
//运行之后 l={5,4,3,3,2,1,1}

l.sort(op);
//以 op 为准则, 将所有元素排序

sort 和 unique 函数结合
正常来说是不会用到 unique 函数的, 他一般和 sort 函数搭配使用, 达到将容器中相同的多余元素删除的效果(真正意义上的排重)
例如:

l={2,5,1,6,1,3,2,4,1,5,6};
直接执行 unique 函数是不能真正做到排重的
只有先进行 sort 排序, 再执行 unique 函数, 才能达到要求
l.sort();
l.unique();
执行之后, l={1,2,3,4,5,6}

写在最后:
op 是自定义的操作依据, 毕竟C++不可能把所有情况都内置在函数里, 要想实现比较复杂的准则只能自己写个 op 函数
我只会最简单的使用op, 因此在文章中并没有进行详细介绍.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值