写在前面:近期正在学习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 函数随机访问容器内元素,只能通过迭代器访问
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}
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}
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}
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的区别
push系列与insert的区别
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
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 中插入的内容删除
l.erase(l.begin());
//删除位置上的元素, 返回迭代器, 指向下一个元素
//例: l={1,2,3}
//运行之后 l={2,3}
l.erase(l.begin(), l.end());
//删除区间内的元素
//例: l={1,2,3}
//运行之后 l={}
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}
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 函数只将相邻的相同元素删除, 没有真正达到排重的效果
l.reverse();
//翻转容器
//例:l={1,2,3,4}
//运行之后, l={4,3,2,1}
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, 因此在文章中并没有进行详细介绍.