简单介绍了冒泡排序、选择排序、插入排序、快速排序、堆排序和C++中sort函数的实现及复杂度。
一、冒泡排序
方法一
void Bubble_Sort(int a[],int len) {
for (int i = 0;i < len - 1;i++) {
for (int j = 0;j < len - 1 - i;j++) {
if (a[j] > a[j + 1]) {
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
方法二(优化)
设置一个标志,每次外层循环时判断整个数组是否已经排好序,是则终止循环,结束。
void Bubble_Sort_2(int a[], int len) {
int flag = 0;
for (int i = 0;i < len - 1;i++) {
for (int j = 0;j < len - 1 - i;j++) {
if (a[j] > a[j + 1]) {
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
flag = 1;
}
}
if (flag == 0) {
return;
}
}
}
复杂度
时间复杂度:
O
(
N
2
)
O(N^2)
O(N2)
空间复杂度:
O
(
1
)
O(1)
O(1)
二、选择排序
基本思想:为每一个位置选择未排序的序列中的最小(或最大)的元素并交换。
void Select_Sort(int a[],int len) {
for (int i = 0;i < len - 1;i++) {
int min = a[i]; //记录最小值
int min_index = i; //记录最小值对应的索引
for (int j = i + 1;j < len;j++) { //找到未排序序列中最小的值
if (min > a[j]) {
min = a[j];
min_index = j;
}
}
if (i != min_index) { //如果最小的不是自己则交换
int temp = a[i];
a[i] = min;
a[min_index] = temp;
}
}
}
复杂度
时间复杂度: O ( N 2 ) O(N^2) O(N2)
空间复杂度: O ( 1 ) O(1) O(1)
三、插入排序
基本思想:将有序序列末端的元素插入到有序序列中相应的位置。
void Insert_Sort(int a[],int len) {
for (int i = 0;i < len;i++) {
for (int j = i;j > 0;j--) {
if (a[j] < a[j - 1]) { //交换元素
int temp = a[j];
a[j] = a[j - 1];
a[j -1] = temp;
}
else
break;
}
}
}
复杂度
时间复杂度: O ( N 2 ) O(N^2) O(N2)
空间复杂度: O ( 1 ) O(1) O(1)
四、快速排序
void Quick_Sort(int a[],int left,int right) {
if (left >= right)return;
int i = left;
int j = right;
int k = a[i]; //以最左边的元素为基准
while (i < j) {
while (i < j&&a[j] >= k) //找右边的元素中比基准元素小的元素
{
j--;
}
a[i] = a[j];
while (i < j&&a[i] <= k) //找左边的元素中比基准元素大的元素
{
i++;
}
a[j] = a[i];
}
a[i] = k;
Quick_Sort(a, left, i - 1);
Quick_Sort(a,i+1,right);
}
复杂度
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
空间复杂度:
O
(
l
o
g
n
)
O(logn)
O(logn)
五、堆排序
为了减少代码量,该算法使用STL库实现堆排序。
- make_heap(_First, _Last, _Comp):
建立堆,当_Comp为less时,建立最大堆,为greater时,建立最小堆。 - push_heap (_First, _Last):
向堆中添加数据。要先在容器(如vector)中添加,再调用push_heap()。 - pop_heap(_First, _Last):
在堆中删除数据。调用完pop_heap()后,再删除容器中的数据。 - sort_heap(_First, _Last):堆排序。
void print_sort(vector<int> a) { //打印结果的函数
for (vector<int>::iterator it = a.begin();it != a.end();it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
int a[10] = { 33,2,1,6,4,2,1,5,18,0 };
vector<int> b(a,a+10);
make_heap(b.begin(),b.end(),greater<int>());//创建最小堆
sort_heap(b.begin(),b.end(),greater<int>());//排序
print_sort(b);
}
排序结果:
往堆中添加数据,先在容器中添加,再调用push_heap():
b.push_back(99); //b是一个vector
push_heap(b.begin(), b.end(), less<int>());
再次排序结果:
删除堆中的数据,先调用pop_heap(),再删除容器中的数据:
pop_heap(b.begin(), b.end(), greater<int>());
b.pop_back();
再次排序结果:
可以发现0被pop掉了。
复杂度
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
空间复杂度:
O
(
1
)
O(1)
O(1)
六、C++中sort函数
sort函数的头文件为#include<algorithm>。
假设有一个数组int a[4]={1,2,3,4},sort(a,a+4)可将a中的元素从小到大进行排序,除此之外,sort函数第三个参数也可以是一个比较函数,下面以PAT中
1015 德才论为例进行解释。
1015 德才论 (25 分)
宋代史学家司马光在《资治通鉴》中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人。凡取人之术,苟不得圣人,君子而与之,与其得小人,不若得愚人。”
现给出一批考生的德才分数,请根据司马光的理论给出录取排名。
输入格式:
输入第一行给出 3 个正整数,分别为:N(≤10
5
),即考生总数;L(≥60),为录取最低分数线,即德分和才分均不低于 L 的考生才有资格被考虑录取;H(<100),为优先录取线——德分和才分均不低于此线的被定义为“才德全尽”,此类考生按德才总分从高到低排序;才分不到但德分到线的一类考生属于“德胜才”,也按总分排序,但排在第一类考生之后;德才分均低于 H,但是德分不低于才分的考生属于“才德兼亡”但尚有“德胜才”者,按总分排序,但排在第二类考生之后;其他达到最低线 L 的考生也按总分排序,但排在第三类考生之后。
随后 N 行,每行给出一位考生的信息,包括:准考证号 德分 才分,其中准考证号为 8 位整数,德才分为区间 [0, 100] 内的整数。数字间以空格分隔。
输出格式:
输出第一行首先给出达到最低分数线的考生人数 M,随后 M 行,每行按照输入格式输出一位考生的信息,考生按输入中说明的规则从高到低排序。当某类考生中有多人总分相同时,按其德分降序排列;若德分也并列,则按准考证号的升序输出。
我们用一个结构体对学生进行存储:
struct Student{
char num[10]; //学号
int d,c,s; //德才和总分;
int flag; //学生所在类别
}stu[100010];
现要对若干学生根据题目中的要求对学生进行排序,我们按照题目要求编写一个比较函数:
bool cmp(Student a,Student b){
if(a.flag!=b.flag){
return a.flag<b.flag; //类别小的在前面
}
else if(a.s!=b.s){
return a.s>b.s; //类别一样时总分大的在前面
}
else if(a.d!=b.d){
return a.d>b.d; //总分相同时德分大的在前面
}
else{
return strcmp(a.num,b.num)<0; //德分一样时准考证小的在前面
}
}
然后我们就可以对stu数组中的若干学生使用sort函数进行排序了:
sort(stu,stu+N,cmp);
这样输出结果就可以了,别忘了先引用头文件#include<algorithm>。