9.3常用的库函数

STL提供了大约70个通用函数,包含在<algorithm>,<numeric>,<functional>等头文件中,这些函数实现了排序、二分查找等算法,能够应用于STL中的容器和数组

1.排序函数

在排序时,参与排序的元素称为记录,记录是进行排序的基本单位。所有待排序记录的集合称为序列。所谓排序就是将序列中的记录按照特定的顺序排列起来

排序可以调用STL中的sort函数。sort函数的原型为:
sort(start, end, cmp);
参数的含义如下:
①start表示整个序列存储空间的起始地址,如果用数组a存储序列,则start参数的值就是数组名
②end表示整个序列存储空间结束后下一个字节的地址,如果序列(设为数组a)中记录个数为n,则end参数的值就是a+n。注意,end不是序列最后一个记录的存储地址,而是最后一个记录结束后下一个字节的地址 
sort(start, end, cmp);
参数的含义如下:
③cmp参数是一个函数,其作用是指定排序时比较记录之间大小关系的规则。如果参与排序的记录可以直接比较大小,比如基本数据类型(如int,double等),cmp参数可以不填,此时默认为从小到大排序如果要实现从大到小排序,则cmp参数可以填greater<int>()、greater<double>()等。如果参与排序的记录是结构体类型,不能直接比较大小,则必须定义cmp函数。注意,函数名可以换成别的名字,因为它是作为sort函数的一个参数,但一般建议还是取cmp

假设结构体类型Type,包含m1,m2,m3这三个成员。如果要按m1成员从小到大排序,则cmp函数应该定义成:

bool cmp(Type s1, Type s2)
{
    return s1.m1 < s2.m1;
}

如果要按m1成员从大到小排序,只需把return语句改成:return s2.m1 < s1.m1

对从小到大排序,cmp函数也可以定义成: 

bool cmp(Type s1, Type s2)
{
    if(s1.m1 < s2.m1) return ture;
    else return false;
}

如果要实现多级排序,比如先按m1成员从小到大排序,m1成员相同再按m2成员从小到大排序,则cmp函数应该定义成:

bool cmp(Type s1, Type s2)
{
    if(s1.m1!=s2.m1) return s1.m1 < s2.m1;
    else return s1.m2 < s2.m2;
}

其思想是:如果s1和s2的m1成员不相同,则已经分出大小了,只需返回它们的m1成员的大小关系;否则(即m1成员相同),再返回它们的m2成员的大小关系
注意,cmp函数第一行也可以写成:
bool cmp(const Type s1, const Type s2)
或:
bool cmp(const Type &s1, const Type &s2)    //&表示引用,代表形参与实参相同 

2.二分查找函数

假设有一个整型数组a,其元素个数为m,现在要在该数组中查找某个数num。当a中元素是无序的,即没有按从小到大或从大到小顺序排序,只能按顺序查找,其时间复杂度为O(n)。当a中元素是有序的,二分查找能极大的加快查找速度,二分查找的时间复杂度为O(logn)。二分查找适用于元素个数n很大、且需要频繁查找的情形

二分查找(折半查找)的思想是:先将num与a数组正中的元素进行比较,如果相等,则已经找到;如果num比正中的元素还要小,则如果num存在,则肯定位于前半段,不可能位于后半段,所以不需要考虑后半段;否则,um肯定位于后半段。在前半段(或后半段)查找时,又是将num与正中的元素进行比较,…。一直到找到num,或者判断num不存在为止

在C++的头文件<algorithm>里定义了以下三个二分查找函数:

①lower_bound(begin, end, num):如果数组中的元素是从小到大排序,则从数组的begin位置到end-1位置二分查找第一个大于或等于num的元素,返回该元素的地址;如果元素是从大到小排序,则查找第一个小于或等于num的元素,返回该元素的地址

②upper_bound(begin, end, num):如果数组中的元素是从小到大排序,则从数组的begin位置到end-1位置二分查找第一个大于num的元素,返回该元素的地址;如果元素是从大到小排序,则查找第一个小于num的元素,返回该元素的地址

③binary_search(begin, end, num):返回是否存在num这么一个数,是一个bool值

注意:1)lower_bound和upper_bound函数返回的都是地址,必须减去起始地址,得到的才是位置;2)如果没有找到要查找的数值,lower bound:和upper_bound函数就会返回一个假想的插入位置。例:

int a[6] = {0, 5, 9, 9, 15, 17};
int position1 = lower_bound(a, a+6, 9) - a;  //找到第一个>=9的数返回地址
int position2 = upper_bound(a, a+6, 9) - a;  //找到第一个>9的数返回地址
cout << position1 << endl;  //输出2
cout << position2 << end2;  //输出4

3.生成序列全排列的函数

如果从n个不同元素中取n个排成一列,所有的排列情况就是全排列,记为P(n, n)。易知,P(n,n)=n!

对全排列中的n!个排列,可以按字典序排序。所谓字典序,就是先按第一个元从小到大排序,第一个元素相同再按第二个元素从小到大排序,以此类推

例如,假设n=3,且3个元素为1,2,3,则3!=6个排列如下:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1 

又如,假设n=4,且4个元素为a, g, m, p(约定a<g<m<p),这24个排列如下 

在编程解题时,有时需要生成一个序列的所有排列,用于枚举或搜索

生成序列全排列的2个函数:next_permutation和prev_permutation。这两个函数都是包含在头文件<algorithm>里,它们的作用是一样的,区别就在于前者求的是当前排列的下一个排列,后者求的是当前排列的上一个排列。至于这里的“前一个”和“后一个”,可以理解为序列字典序上的前一个和后一个排列

这2个函数的原型为:
bool prev_permutation(iterator start, iterator end);
bool next_permutation(iterator start, iterator end);

参数start和end类似于sort函数的2个参数,start表示整个序列存储空间的起始地址,end表示整个序列存储空间结束后下一个字节的地址,如果序列(设为数组a)中记录个数为n,则end参数的值就是a+n

如果当前序列不存在前一个下一个排列时,函数返回false,否则返回true

注意,新的排列仍然是存储在原序列中 

例如,对于上一节的例子,可以用以下代码生成a, g, m, p四个元素的全排列(用字符表示这四个元素)

char arr[20] = "agmp";
do{
    cout << arr[0] << " " << arr[1] << " " << arr[2] << " " << arr[3] << endl;
}
while(next_permutation(arr, arr + 4));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值