排序算法的特性:
线性排序:计数排序
逆序数对:归并排序
第K大数:快速排序
排序算法复杂度的下限是O(nlogn),这是基于比较的排序方法。
而线性的复杂度是O(n),这是不通过比较而进行排序的方法。
我们需要明确知道序列中所有数的一个范围 r ,复杂度就是O(n + r)。
好吧这样还是比较抽象,以下面的栗子可以快速看懂。
这里是几个数字,需要对其进行排序,采用计数排序的办法,这么多数字都是0~9的数字,那么开一个数组,大小是数据的范围。本题数组大小为10,因为是0~9,10个数字。
然后统计序列中每个数字出现的次数,0出现0次,1出现了1次......
现在线性扫描一遍辅助数组,即可得到排序好的序列,整个过程只需两次线性扫描。
看一下杭电这道题:http://acm.hdu.edu.cn/showproblem.php?pid=1425
1.先定义一个arr存放输入的序列
2.定义一个辅助数组number,但是数据中有负数,所以将原区间整个向右平移,范围变成0~1000000,而平移的范围设定一个常量RANGE
3.然后输入数据,输入的同时,将数据放入“ 桶 ”内。这里我将辅助数组称为桶,比较形象。
4.然后对桶里面的数据进行遍历,遍历的同时将数据从小到大放回原来的数组
5.由于要从大到小排序,所以输出的时候从n-1开始倒着遍历
本题有个坑,就是最后一个数字后面没有空格,而其余数字有空格!!!
6.有个点需要注意,就是,辅助数组每次都需要清零,这里使用memset函数,记得头文件加上 cstring。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 1e6 + 10;
const int RANGE = 5e5;
int arr[MAXN];
int number[MAXN];
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
memset(number,0,sizeof(number));
for(int i = 0;i < n; ++i){
scanf("%d",&arr[i]);
number[arr[i] + RANGE]++;//把数字放进桶里面,记得要加上位移距离
}
//接下来就是要把从小到大的排序的数字放进原来的arr数组里面
int index = 0;
for(int i = 0; i < MAXN; ++i){//遍历number数组
while(number[i]--){
arr[index] = i - RANGE;
index++;
}
}
for(int i = n-1; i >= n - m; --i){
if(i == n - m){ //这里有坑,最后一个数字不需要加空格其余的要加空格
printf("%d",arr[i]);
}else{
printf("%d ",arr[i]);
}
}
printf("\n");
}
return 0;
}