前言
在寒假第三周的ACM集训队里学习了sort快排,手写快排和归并排序,其中在打比赛时,我们直接调用c++写好的sort函数即可。简单实用,以下详谈
提示:数据结构(C语言版 第 2 版)P243
一、sort 是什么
快速排序(Quick Sort)是由冒泡排序改进而得的。在冒泡排序过程中,只对相邻的两个记录进行比较,因此每次交换两个相邻记录时只能消除一个逆序。如果能通过两个(不相邻)记录的一次交换,消除多个逆序,则会大大加快排序的速度。快速排序方法中的一次交换可能消除多个逆序。
该方法的基本思想是:
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
快速排序视频讲解链接http://www.proedu.com.cn/web/shareVideo/index.action?id=1013492&ajax=1
二、sort 的使用
1.头文件及模板
(1)使用sort函数头文件需要#include< algorithm >
(2)sort模板含三个参数:sort (begin,end,cmp)
- 参数begin:要排序数组的起始地址(第一个数据的地址)
- 参数end:最后一个数据的下一个数据的地址
- 参数cmp:若这个参数不写,默认为升序
讲一下 cmp,这其实也是一个函数,cmp参数不写,默认升序;cmp函数里写return a<b,也是升序;cmp函数里写return a>b,然后才实现降序
2.代码实现
#include<iostream>
#include<algorithm>
using namespace std;
bool cmp(int a,int b) //这四行不写默认是升序
{ //要想实现降序,只需要改变一个符号即可
return a < b; // return a > b;
} //此时主函数运行结果则是 6 5 3 2 1
int main()
{
int a[]={6, 5, 2, 1, 3};
sort(a, a+5, cmp);
for(int i=0; i<5; i++)
cout << a[i] << " "; //运行结果1 2 3 5 6
}
要觉得 cmp 麻烦,也可以不用自己写cmp函数就可以实现排序
升序:sort(begin,end,less());
降序:sort(begin,end,greater());
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int a[]={6, 5, 2, 1, 3};
sort(a, a+5, greater<int>());//降序
for(int i=0; i<5; i++)
cout << a[i] << " "; //运行结果 6 5 3 2 1
sort(a, a+5, less<int>());//升序
for(int i=0; i<5; i++)
cout << a[i] << " "; //运行结果1 2 3 5 6
return 0;
}
3.适用范围扩充
(1)完成字符的排序
利用迭代器便可实现:
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
string a = "hello world";
sort(a.begin(), a.end());
cout << a; //运行结果 空格dehllloorw
return 0;
}
(2)完成字符串的排序
这里是指五个字符串的排序,所以要用到二维数组
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main()
{
string a[5];
for(int i=0; i<5; i++)
cin >> a[i];
sort(a, a+5);
cout << endl;
for(int i=0; i<5; i++)
cout << a[i]<< endl;
return 0;
}
(3)对结构体进行排序
#include<iostream>
#include<algorithm>
using namespace std;
struct wzs
{
int x;
int y;
};
bool cmp(wzs a, wzs b)
{
if(a.x == b.x)
return a.y>b.y;
else
return a.x>b.x;
}
int main()
{
wzs a[4]={{2,1}, {3,3}, {6,3}, {3,2}};
sort(a,a+4,cmp);
for(int i=0; i<4; i++)
cout << a[i].x << " " << a[i].y << endl;
return 0;
}
其实这都是基于sort快排的一般用法来实现的。
对字符排序只是把数字换成了字符;
对字符串排序只是把数字换成了字符串;
对结构体排序只是把数字换成了结构体;
本质就是sort函数,只要掌握此模板即可。
4.算法分析
(1)时间复杂度
从快速排序算法的递归树可知,快速排序的趟数取决于递归树的深度
(2)空间复杂度
最好情况下的空间复杂度为O(log2 n)
最坏情况下的空间复杂度为O(n)
快速排序是递归的,执行时需要有一个栈来存放相应的数据。最大递归调用次数与递归树的深度一致,所以最好情况下的空间复杂度为O(log2 n),最坏情况为O(n)
5.算法特点
- 记录非顺次的移动导致排序方法是不稳定的
- 排序过程中需要定位表的上界和下界,所以适合用于顺序结构,很难用于链式结构
- 当 n 较大时,在平均情况下快速排序是所有内部排序中速度最快的一种所以其适合初始记录无序,n 较大时的情况(数据越乱越好)
总结
基于冒泡排序,出现了各种快排,而本次的 sort 快排理解还是比较简单的,只需记住模板再多多练习即可
附:练习题加冒泡排序
//洛谷 P1104生日练习
#include<iostream>
#include<algorithm>
#define N 110
using namespace std;
struct sr
{
string name;
int year, month, day, x;
}a[N];
bool cmp(sr a, sr b)
{
if(a.year == b.year)
{
if(a.month == b.month)
{
if(a.day == b.day)
return a.x > b.x;
else
return a.day < b.day;
}
else
return a.month < b.month;
}
else
return a.year < b.year;
}
/*其实这样更简洁也更好看(只要return了就不会再执行下一条语句了不是吗?
bool cmp(sr a,sr b)
{
if(a.year!=b.year) return a.year < b.year;
if(a.month!=b.month) return a.month < b.month;
if(a.day!=b.day) return a.day < b.day;
return a.x > b.x;
}
*/
int main()
{
int n;
cin >> n;
for(int i=0; i<n; i++)
{
cin >> a[i].name >> a[i].year >> a[i].month >> a[i].day;
a[i].x = i+1;
}
sort(a, a+n, cmp);
for(int i=0; i<n; i++)
cout << a[i].name << endl;
return 0;
}