STL 库中的奇技淫巧

STL 是惠普实验室开发的一系列软件的统称,可以理解为一些容器的集合。STL的目的是标准化组件,这样就不用重新开发,可以使用现成的组件。STL 现在是C++的一部分,因此不用额外安装什么。

STL 中的库

在 C++标准中,STL 被组织为下面的 17 个头文件:<algorithm>、<deque>、<functional>、<iterator>、<array>、<vector>、<list>、<forward_list>、<map>、<unordered_map>、<memory>、<numeric>、<queue>、<set>、<unordered_set>、<stack>和<utility>

#include<algorithm>

它主要是对数组类型(或类似)的数据结构进行操作。

for_each(start , end , function)

解释

这个我只在 C++ primer 见过。意思是,从某个容器的 start 指针,到这个容器的 end 指针,均执行 function 函数。

实例

#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
int ia[] = { 1,2,3 };
vector<int>ivec(ia, ia + sizeof(ia) / sizeof(int));
void print(int& x)
{cout << x << endl;
}
int main()
{for_each(ivec.begin(), ivec.end(), print);return 0;
}

输出结果

1
2
3

相当于:将这个容器内的一个元素传入第一个未被占用的参数。缺参数?看一下这个例子。

#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
int ia[] = { 1,2,3 };
vector<int>ivec(ia, ia + sizeof(ia) / sizeof(int));
struct print
{const char* _prefix;print(const char* prefix) :_prefix(prefix) {}void operator()(int elem){cout << _prefix << elem << endl;}
};
int main()
{for_each(ivec.begin(), ivec.end(), print("Element:"));return 0;
}

输出结果

Element:1
Element:2
Element:3

is_sorted(start,end)

解释

返回一个 bool 值,判断这个区间是否排序。

#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{int a[5] = { 1,3,4,2,5 };cout << is_sorted(a, a + 5);
}

输出结果

0

is_sorted_until(start,end)

解释

std::is_sorted_until用于查找范围 [first,last) 中的第一个未排序元素。它将迭代器返回到范围中的第一个未排序元素,因此在first和返回的迭代器之间的所有元素都进行了排序。

#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{int a[5] = { 1,3,4,2,5 };cout << is_sorted_until(a, a + 5) << endl;cout << *is_sorted_until(a, a + 5);
}

输出结果

0078F870
2

sort(start,end,function) 和 stable_sort(start,end,function)

解释

使得 start~end 按 function 规则排序。无返回值。复杂度为稳定 O(nlogn),其中 sort 为不稳定排序。function 当且仅当该容器为数组且 function 未定义时默认为从小到大。

#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{int a[5] = { 1,3,4,2,5 };sort(a, a+5);for (int i = 0; i < 5; i++)cout << a[i] << " ";
}

输出

1 2 3 4 5

lower_bound(start,end,val) & upper_bound(start,end,val)

解释

  • lower_bound(start,end,val):返回一个不小于 value 的最小指针
  • upper_bound(start,end,val):返回一个大于 value 的最小指针。
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{int a[5] = { 1,3,4,2,5 };cout << lower_bound(a, a + 5, a[1]) << endl;cout << *lower_bound(a, a + 5, a[1]) << endl;cout << upper_bound(a, a + 5, a[1]) << endl;cout << *upper_bound(a, a + 5, a[1]) << endl;
}

输出结果

012FF7A4
3
012FF7A8
4

heap

heap(堆)就是用数组实现的二叉树,所以它没有使用父指针或者子指针。堆根据 “堆属性” 来排序,“堆属性” 决定了树中节点的位置。
堆的常用方法:

  • 构建优先队列
  • 支持堆排序
  • 快速找出一个集合中的最小值(或者最大值)。

heap属性

堆属性分为两种:

  • 最大堆。在最大堆中,父节点的值比每一个节点的值都要大。
  • 最小堆。在最小堆中,父节点的值比每一个子节点的值都要小。

但是heap没有迭代器,heap的所有元素都必须遵循特别的 complete binary tree(完全二叉树,整棵binary tree除了最底层的叶节点之外是填满的,而最底层的叶节点由左至右不得有空隙)排序规则,所以heap不提供遍历功能,也不提供迭代器。

堆和普通树的区别

  • 节点的顺序:

    • 在二叉搜索树中,左子节点必须比父节点小,右子节点必须比父节点大。
    • 但是,在堆中并非如此。在最大堆中两个子节点都必须比父节点小,而在最小堆中,它们都必须比父节点大。
  • 内存占用
    • 普通树占用的内存空间比它们存储的数据要多,必须为节点对象以及左右子节点指针分配足够的内存。
    • 堆仅仅使用一个数据来村塾数组,且不使用指针。

heap算法

push_heap()

push_heap()要求新加入的元素一定要放在最下一层作为叶节点,并填补在由左至右的第一个空格,也就是把新元素插入在底层vector的end()处,如下图所示。

pop_heap()

在max-heap中,最大值必然在根节点,pop操作取走根节点之后,为了满足complete binary tree的条件,需要将最下一层最右边的叶节点拿掉,而取走的根节点其实是移至底部容器vector的最后一个元素。为满足max-heap的条件,执行下溯程序:

  1. 将根节点(最大值被取走后形成一个“洞”)填入失去生存空间的叶节点值,
  2. 再将它拿来和其两个子节点比较键值,并与较大子节点对调位置,直到这个“洞”的键值大于左右两个子节点,或者到下放至叶节点为止。如下图所示:

注意:pop_heap之后,最大值只是被置放在底部容器的最尾端,尚未被取走。如果要取其值,可使用底部容器(vector)所提供的back()操作函数。如果要移除它,可使用底部容器(vector)所提供的pop_back()操作函数。

sort_heap()

每次使用pop_heap可获得heap中键值最大的元素,如果持续对整个heap做pop_heap操作,每次将操作范围从后向前缩减一个元素,因为pop_heap会把键值最大的元素放在底部容器的最尾端,当整个程序执行完毕时,就形成一个递增序列,如下图所示。

注意:排序后,原来的heap就不再是一个合法的heap。

make_heap()

这个算法用来将一段现有的数据转化为一个heap。

例1 底层以vector完成

#include<vector>
#include<iostream>
#include<algorithm>using namespace std;void TestHeap1()
{int arr[9] = { 0, 1, 2, 3, 4, 8, 9, 3, 5 };vector<int> v1(arr, arr + 9);cout << "vector data:";for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;//make_heapmake_heap(v1.begin(), v1.end());cout << "make heap后:";for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;//push_heapv1.push_back(7);push_heap(v1.begin(), v1.end());cout << "push 7 heap后:";for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;//pop_heappop_heap(v1.begin(), v1.end());cout << "pop heap:";cout << v1.back() << endl; //最大值9被放在vector的最尾端,但是没有取走v1.pop_back();cout << "pop back后:";for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;//sort_heapsort_heap(v1.begin(), v1.end());cout << "sort heap后:";for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;
}int main()
{TestHeap1();system("pause");return 0;
}
输出结果
vector data:0 1 2 3 4 8 9 3 5
make heap后:9 5 8 3 4 0 2 3 1
push 7 heap后:9 7 8 3 5 0 2 3 1 4
pop heap:9
pop back后:8 7 4 3 5 0 2 3 1
sort heap后:0 1 2 3 3 4 5 7 8

例2 底层以array完成

#include<iostream>
#include<algorithm>using namespace std;void TestHeap2()
{int arr[9] = { 0, 1, 2, 3, 4, 8, 9, 3, 5 };make_heap(arr, arr + 9);cout << "make heap后:";for (int i = 0; i < 9; i++){cout << arr[i] << " ";}cout << endl;//sort_heapsort_heap(arr, arr + 9);cout << "sort make后:";for (int i = 0; i < 9; i++){cout << arr[i] << " ";}cout << endl;//经过排序之后的heap,不再是个合法的heap//重新再做一个heapmake_heap(arr, arr + 9);cout << "再一次make heap后:";for (int i = 0; i < 9; i++){cout << arr[i] << " ";}cout << endl;//pop_heappop_heap(arr, arr + 9);cout << "pop heap后,查看arr[8]的值:";cout << arr[8] << endl;
}int main()
{TestHeap2();system("pause");return 0;
}
输出结果
make heap后:9 5 8 3 4 0 2 3 1
sort make后:0 1 2 3 3 4 5 8 9
再一次make heap后:9 8 5 3 3 4 2 1 0
pop heap后,查看arr[8]的值:9

最大(max/max_element)/最小操作(min/min_element)。

解释

  • max(num1,num2)
  • min(num1,num2);
  • max_element(start,end)
  • min_element(start,end);
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{int a[5] = { 1,3,4,2,5 };cout << max_element(a, a + 5) << endl;cout << *max_element(a, a + 5) << endl;cout << min_element(a, a + 5) << endl;cout << *min_element(a, a + 5) << endl;
}

输出结果

00AFF7A4
5
00AFF794
1

#include<vector>

是在 C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。可以为一大堆有序容器建立容器, 这是一个动态数组,节约空间。

vector<int>vec;            //创建vec.push_back(a);       //尾部插入元素:a 为一个元素vec[0];              //访问:使用数组[]vec.size();           //求大小vec.clear();           //清空vec.insert(pos, val);           //v.插入:在 pos 的位置的前面插入 val 元素vec.reverse(start, end);        //反转:将[start,end)之间的元素顺序颠倒。需要头文件<algorithm>vec.erase(pos);          //vi.删除:删除第 pos + 1 个元素。
vec.erase(start, end);          //或者:删除[start, end)之间的所有元素。//迭代器:
vector<int>::iterator it;
for (it = vec.begin(); it != vec.end(); it++)cout << *it << endl;

#inlcude<map>

map 建立的是一个映射,可应用于离散化模型。

插入

// 定义一个map对象
map<int, string> mapStudent;// 第一种 用insert函數插入pair
mapStudent.insert(pair<int, string>(000, "student_zero"));// 第二种 用insert函数插入value_type数据
mapStudent.insert(map<int, string>::value_type(001, "student_one"));// 第三种 用"array"方式插入
mapStudent[123] = "student_first";
mapStudent[456] = "student_second";if (it != m.end())m.erase(it);

查找

map<int, int>::iterator it;
it = m.find(num);

删除

if (it != m.end())m.erase(it);

#inlcude<set>

STL 对这个序列可以进行查找,插入删除序列中的任意一个元素,而完成这些操作的时间同这个序列中元素个数的对数成比例关系,并且
当游标指向一个已删除的元素时,删除操作无效。

而一个经过更正的和更加实际的定义应该是:一个集合(set)是一个容器,它其中所包含的元素的值是唯一的。这在收集一个数据的具体值的时候是有用的。集合中的元素按一定的顺序排列,并被作为集合中的实例。

一个集合通过一个链表来组织,在插入操作和删除操作上比向量(vector)快,但查找或添加末尾的元素时会有些慢。具体实现采用了红黑树的平衡二叉树的数据结构。

//插入:
s.insert(num);
//删除:
s.erase(num);
//查找:
s.find(num);
//集合运算:
set set_intersection(set1, set2); //交集
set set_union(set1, set2); //并集
set set_difference(set1, set2); //差集

ACM算法小技巧

判断是否为整数

使用Math.round(取最近的整数)、Math.ceil(向上取整)、Math.floor(向下取整)判断

整数取整后还是等于自己。利用这个特性来判断是否是整数,Math.floor示例,如下

#include <iostream>
#include<cmath>
bool function (double obj) {return floor(obj) == obj;
}
int main()
{double t;std::cin >> t;std::cout << function(t);
}

输入输出

输入 3
1
输入 3.3
0

万能头文件

#include<bits/stdc++.h>

快读读入技巧

int read() //快读
{int x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return x*f;
}inline int read() //我喜欢快读
{int num = 0;char c;bool flag = false;while ((c = getchar()) == ' ' || c == '\n' || c == '\r');if (c == '-') flag = true;elsenum = c - '0';while (isdigit(c = getchar()))num = num * 10 + c - '0';return (flag ? -1 : 1) * num;
}

欧几里得算法

欧几里得算法又称辗转相除法,是指用于计算两个非负整数a,b的最大公约数。应用领域有数学和计算机两个方面。计算公式 gcd(a,b)=gcd(b,amodb)gcd(a,b) = gcd(b,a mod b)gcd(a,b)=gcd(b,amodb) 。

inline int gcd(int x,int y)
{if(y==0) return x;return gcd(y,x%y);
}

奇技淫巧-STL 库 ACM算法小技巧(持续更新中~~~)相关推荐

  1. Python日常小技巧(持续更新中)

    目录 快速定位元组内容 对字典进行排序 json的获取(dumps,dump,loads,load) 查找字典中相同的key 统计列表中元素的个数 字典按输入顺序输出 历史记录的存储 对有多个分割符的 ...

  2. 有关树的常见算法汇总【持续更新中】

    关于数据结构中--树的算法汇总[持续更新中] 0.树的顺序和链式存储结构 [完成] 1.树的前序遍历(递归和非递归java实现) [完成] 2.树的中序遍历(递归和非递归java实现) [完成] 3. ...

  3. 小白使用word小技巧-持续更新(以论文服务为主)

    文章目录 写论文时的记录,本人键盘各位置图,仅供参考(事实上,使用word,按一下Alt,可以看到word屏幕上的快捷键提示,记不住就对着按就行了) 1.文字快捷键 : 2.文本的段落样式设置快捷键和 ...

  4. 数据结构与算法复习(持续更新中)

    目录 数组 为什么很多编程语言中数组都从0开始编号? 如何实现随机访问 数组和链表的区别 链表 栈 函数调用栈来保存临时变量,为什么函数调用要用"栈"来保存临时变量呢?用其他数据结 ...

  5. 论文写作排版小技巧(更新中)

    熟练了语法之后,毕业论文其实用 LaTeX 写是最好的,但总有些原因吧. Word 排版是比较蛋疼的.整格式第一件要做的事情就是找学校的官方模板,把正文往上套. 模板解决不了的以及一些写论文时候发现的 ...

  6. Android实用小技巧(持续更新)

    文章目录 给drawableRight设置点击事件 限制EditText可输入的字数,超出后提示文案 解决RecycleView布局中GridLayoutManager和StaggeredGridLa ...

  7. ASP.NET 开发小技巧 (持续更新)

    有时为一些小问题而去查资料.浪费太多的时间,为此把开发中经常遇到的一些小问题.记录下来.供日常开发查询用: 1.项目中使用Forms验证.而有些文件又不需要验证就能访问,最常见的是验证码文件或admi ...

  8. IAR 使用小技巧--持续更新

    1.复制和粘贴几行的部分代码 需求:有时候我们需要复制几行代码的后半部分,不需要复制前半部分. 方法:按住Alt键,再用鼠标拖动就可以复制和粘贴后半部分 2.常用快捷键 烧录程序:Ctrl + D 全 ...

  9. Maven打包小技巧--持续更新

    NO.1 跳过测试,打包指定环境 mvn clean install -Dmaven.test.skip=true -P dev 其中:clean将target目录中的文件移除: install根据配 ...

最新文章

  1. Failed to fetch http://mirrors.cloud.aliyuncs.com/
  2. boost::geometry::coordinate_system用法的测试程序
  3. View4.5测试参考文档1--测试环境规划
  4. 解决android自定义标题充满的问题
  5. numpy矩阵乘法_NumPy矩阵乘法
  6. SQL:postgresql中st_union合并多条geom数据
  7. 初窥JQuery(二)-事件机制(1)
  8. 如何批量将 Excel 转换为 jpeg、png、bmp 图片
  9. 智能爆炸的真实(下)
  10. postman 解决Could not send request
  11. 东财《领导科学X》综合作业
  12. ESX通过命令行重启虚拟机
  13. win10触摸板双指单击不能唤出右键菜单
  14. JavaScript打造很酷的图片放大效果实例代码
  15. windows命令行下schtasks创建定期任务
  16. hmmer 使用(转载)
  17. NGINX 的域名解析缓存
  18. BUUCTF 派大星的烦恼
  19. Apache Kylin 是什么?
  20. 信安软考 第八章 防火墙技术与原理运用

热门文章

  1. c#父窗体子窗体之间传值
  2. openssl的man中文文档
  3. 多类型文件的上传和下载
  4. ECDSA host key for vvv.vvv.vvv.vvv has changed and you have requested strict checking.
  5. [转] LTE载波聚合CA的优化 //LTE CA 学习笔记
  6. 拿什么拯救你,我的ie
  7. 将RGB图像转为YCbCr,并显各通道图片
  8. 正面开战:今日头条将封禁微信、微博等账户推广
  9. websocket传输数据大小限制_websocket设置传输大小
  10. Linux编程基础:第2章命令与开发工具 课后习题