一、计数排序
计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
例
#include<iostream>
using namespace std;
int a[1010]={0},n,m,tmp;
int main(){
cin>>n>>m;
for(int i=0;i<m;i++){
cin>>tmp;
a[tmp]++;
}
for(int i=0;i<=n;i++){
for(int j=0;j<a[j];j++){
cout<<i<<' ';
}
}
cout<<endl;
return 0;
}
按计数排序,只需要开一个大小不小于n的数组作为票箱,依次读入票箱,然后将选票号数加到对应票箱中,最后按照每个票箱的数量输出候选人偏号即可。整个过程中甚至不需要存储一张选票。
计数排序基于分类而非比较的排序,不依赖排序对象之间的直接大小比较。
二、选择排序
思路:n次大循环,第i次大循环中,用小循环寻找数列中第i小的元素。如果发现更小的数字,则交换至第i个位置。 事实上,由于前i-1项已经排序完毕,第i小的元素等价于第i至第n 项中的最小元素。 特点:思路简单,实现更简单。 每次迭代都能保证至少一个(最小)元素的位置被确定。 前i个元素有序,且为最小的i个元素 时间复杂度为O(n的2次方),空间复杂度O(n)
for (int i = 0; i < n - 1; i++)
for (int j = i + 1; j < n; j++) if (a[j] < a[i]) swap(a[i], a[j]);
实现过程如下;
三、冒泡排序
思路:不超过n次大循环;每次大循环,按照顺序比较相邻元素并 交换,直到序列有序。 特点: 总交换次数恰为逆序对数。 每次迭代都能保证至少一个(最大)元素的位置被确定。 后i个元素有序,且为最大的i个元素。 时间复杂度为O(n的2次方),空间复杂度O(n)
for(int i=0;i<n;i++){
for(int j=0;j<n-i-1;j++){
if(a[j]>a[j+1]){
int p=a[j];
a[j]=a[j+1];
a[j+1]=p;
}
}
}
实现过程如下
四、插入排序
思路:n次大循环;第i次大循环将第i个元素向前交换,直至左侧 元素不大于它,或抵达数列首部。 特点:前i个元素有序。但是直到排序完成,不能保证任何一个元 素的最终位置被确定(设想最小元素在数列尾部)。 可以用来动态维护前k小元素,单次插入时间复杂度O(n) 。在此场 景下,第 k+ 1小的元素将不会右移,而是被直接丢弃。 可以用来理牌
for(int i=1;i<n;i++){
int now=a[i];
for(int j=i-1;j>=0;j--){
if(a[j]>now)
a[j+1]=a[j];
else break;
a[j+1];
}
}
选择、冒泡、排序三种排序时间复杂度并不佳,如果数据量过大,使用这三种算法会耗费大量时间
五、插入排序
void qsort(int a[],int l,int r){
int i=l,j=r,flag=a[(l+r)/2];
do{
while(a[i]<flag)i++;//从左边比哨兵大的数
while(a[j]>flag)j--;//从右边比哨兵小的数
if(i<=j){
swap(a[i].a[j])
i++;
j--;
}
}while(i<=j);
if(l<j)qsort(a,l,j);
if(i<r)asort(a,i,r);
}
快速排序主要采用二分法,在极端条件下时间复杂度为O(n的2次方),实际上复杂度为O(nlog n)