奇技淫巧-STL 库 ACM算法小技巧(持续更新中~~~)
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的条件,执行下溯程序:
- 将根节点(最大值被取走后形成一个“洞”)填入失去生存空间的叶节点值,
- 再将它拿来和其两个子节点比较键值,并与较大子节点对调位置,直到这个“洞”的键值大于左右两个子节点,或者到下放至叶节点为止。如下图所示:
注意: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算法小技巧(持续更新中~~~)相关推荐
- Python日常小技巧(持续更新中)
目录 快速定位元组内容 对字典进行排序 json的获取(dumps,dump,loads,load) 查找字典中相同的key 统计列表中元素的个数 字典按输入顺序输出 历史记录的存储 对有多个分割符的 ...
- 有关树的常见算法汇总【持续更新中】
关于数据结构中--树的算法汇总[持续更新中] 0.树的顺序和链式存储结构 [完成] 1.树的前序遍历(递归和非递归java实现) [完成] 2.树的中序遍历(递归和非递归java实现) [完成] 3. ...
- 小白使用word小技巧-持续更新(以论文服务为主)
文章目录 写论文时的记录,本人键盘各位置图,仅供参考(事实上,使用word,按一下Alt,可以看到word屏幕上的快捷键提示,记不住就对着按就行了) 1.文字快捷键 : 2.文本的段落样式设置快捷键和 ...
- 数据结构与算法复习(持续更新中)
目录 数组 为什么很多编程语言中数组都从0开始编号? 如何实现随机访问 数组和链表的区别 链表 栈 函数调用栈来保存临时变量,为什么函数调用要用"栈"来保存临时变量呢?用其他数据结 ...
- 论文写作排版小技巧(更新中)
熟练了语法之后,毕业论文其实用 LaTeX 写是最好的,但总有些原因吧. Word 排版是比较蛋疼的.整格式第一件要做的事情就是找学校的官方模板,把正文往上套. 模板解决不了的以及一些写论文时候发现的 ...
- Android实用小技巧(持续更新)
文章目录 给drawableRight设置点击事件 限制EditText可输入的字数,超出后提示文案 解决RecycleView布局中GridLayoutManager和StaggeredGridLa ...
- ASP.NET 开发小技巧 (持续更新)
有时为一些小问题而去查资料.浪费太多的时间,为此把开发中经常遇到的一些小问题.记录下来.供日常开发查询用: 1.项目中使用Forms验证.而有些文件又不需要验证就能访问,最常见的是验证码文件或admi ...
- IAR 使用小技巧--持续更新
1.复制和粘贴几行的部分代码 需求:有时候我们需要复制几行代码的后半部分,不需要复制前半部分. 方法:按住Alt键,再用鼠标拖动就可以复制和粘贴后半部分 2.常用快捷键 烧录程序:Ctrl + D 全 ...
- Maven打包小技巧--持续更新
NO.1 跳过测试,打包指定环境 mvn clean install -Dmaven.test.skip=true -P dev 其中:clean将target目录中的文件移除: install根据配 ...
最新文章
- Failed to fetch http://mirrors.cloud.aliyuncs.com/
- boost::geometry::coordinate_system用法的测试程序
- View4.5测试参考文档1--测试环境规划
- 解决android自定义标题充满的问题
- numpy矩阵乘法_NumPy矩阵乘法
- SQL:postgresql中st_union合并多条geom数据
- 初窥JQuery(二)-事件机制(1)
- 如何批量将 Excel 转换为 jpeg、png、bmp 图片
- 智能爆炸的真实(下)
- postman 解决Could not send request
- 东财《领导科学X》综合作业
- ESX通过命令行重启虚拟机
- win10触摸板双指单击不能唤出右键菜单
- JavaScript打造很酷的图片放大效果实例代码
- windows命令行下schtasks创建定期任务
- hmmer 使用(转载)
- NGINX 的域名解析缓存
- BUUCTF 派大星的烦恼
- Apache Kylin 是什么?
- 信安软考 第八章 防火墙技术与原理运用
热门文章
- c#父窗体子窗体之间传值
- openssl的man中文文档
- 多类型文件的上传和下载
- ECDSA host key for vvv.vvv.vvv.vvv has changed and you have requested strict checking.
- [转] LTE载波聚合CA的优化 //LTE CA 学习笔记
- 拿什么拯救你,我的ie
- 将RGB图像转为YCbCr,并显各通道图片
- 正面开战:今日头条将封禁微信、微博等账户推广
- websocket传输数据大小限制_websocket设置传输大小
- Linux编程基础:第2章命令与开发工具 课后习题