更多排序算法参见:“10大排序算法” 总结
计数排序
- 针对数据【范围相差不大的整数】的排序。
- 找到数组a最小值Min与最大值Max,相差范围为m。
- 将数组a的值映射到[0,m-1]范围内,作为数组num的下标,则num[i]表示数组a中数值为i+Min的个数,这样排序后的数组可以通过遍历一遍num数组获得。
- 如果要实现稳定性,我们可以对num数组求前缀和得到sum数组,则sum[i]表示a中数值为i+Min的数排到了第sum[i]个。这样倒序遍历一遍a,则sum[a[i]]为稳定排序后a[i]的位置(注意这里的位置是从1开始计数!),--sum[a[i]]。
- 可看出计数排序是稳定排序,时间复杂度为o(m+n),空间复杂度为o(m)
#include<iostream>
using namespace std;
const int inf=0x3f3f3f3f;
void CountSort(int a[], int n)
{
int Min=inf,Max=-1;
for(int i=0;i<n;++i)
{
if(a[i]>Max)
Max=a[i];
if(a[i]<Min)
Min=a[i];
}
int m=Max-Min+1;
int *num = new int[m]();
for(int i=0;i<n;++i)
num[a[i]-Min]++;
for(int i=1;i<m;++i)
num[i]+=num[i-1];
int *sortedArr = new int[n];
for(int i=n-1;i>=0;--i)
{
sortedArr[num[a[i]-Min]-1]=a[i];
num[a[i]-Min]--;
}
for(int i=0;i<n;++i)
a[i]=sortedArr[i];
delete sortedArr;
delete num;
}
int main()
{
int a[100],i,n;
while(cin>>n)
{
for(i=0; i<n; i++)
cin>>a[i];
CountSort(a,n);
for(i=0; i<n; i++)
cout<<a[i]<<" ";
cout<<endl;
}
return 0;
}
桶排序
- 针对计数排序无法处理【浮点型数据】设计
- 建立m个桶,每个桶代表一个浮点范围。则遍历一遍数组,将数组元素放入对应范围的桶,然后对每个桶的元素分别拍排序,可以采用归并排序等,最后按序依次输出每个桶的元素即可。
- 怎么确定m及桶的范围呢?我们可以另m=n,即建立n个桶,除了最后一桶范围是[Max,Max],前面各桶的区间按比例确定:区间跨度 = (最大值-最小值)/ (桶的数量 - 1)
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
void BucketSort(double a[], int n)
{
if(1==n)
return;
double Max=a[0],Min=a[0];
for(int i=1;i<n;++i)
{
if(a[i]>Max)
Max=a[i];
if(a[i]<Min)
Min=a[i];
}
double interval=(Max-Min)/(n-1);
vector<double>v[n];
for(int i=0;i<n;++i)
{
int idx=(a[i]-Min)/interval;
v[idx].push_back(a[i]);
}
for(int i=0;i<n;++i)
sort(v[i].begin(),v[i].end());
int cnt=0;
for(int i=0;i<n;++i)
{
int sz=v[i].size();
for(int j=0;j<sz;++j)
a[cnt++]=v[i][j];
}
}
int main()
{
int i,n;
double a[100];
while(cin>>n)
{
for(i=0; i<n; i++)
cin>>a[i];
BucketSort(a,n);
for(i=0; i<n; i++)
cout<<a[i]<<" ";
cout<<endl;
}
return 0;
}
/*
5 4.5 0.5 2.18 0.84 3.25
*/
基数排序
- 针对计数排序不能对【字符串、范围相差很大的数据】排序的缺陷。如11位的电话号码排序,英文名排序等。
- 对排序元素的每一位分别进行计数排序。
- 时间复杂度 O(k(n*m)) , k为元素的最大位数
- 如果元素的位数不一样,可适当补0。
- 字符串的排序本应从最高位开始比,所以我们应倒着计数排序,因为后一轮会改变前一轮的排序结果。即LSD(低位优先排序)
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int ASCII_RANGE=128;
void radixSort(string a[], int n ,int max_len)
{
string *sortedArr = new string[n];
for(int k=max_len;k>=0;--k)
{
int *num = new int[ASCII_RANGE]();
for(int i=0;i<n;++i)
{
if(a[i].size()<=k)
num[0]++;
else
num[a[i][k]]++;
}
for(int i=1;i<ASCII_RANGE;++i)
num[i]+=num[i-1];
for(int i=n-1;i>=0;--i)
{
int cur;
if(a[i].size()<=k)
cur=0;
else
cur=a[i][k];
sortedArr[num[cur]-1]=a[i];
cout<<num[cur]-1<<" "<<a[i]<<endl;
num[cur]--;
}
delete num;
for(int i=0;i<n;++i)
a[i]=sortedArr[i],cout<<a[i]<<" ";
cout<<endl;
}
delete sortedArr;
}
int main()
{
int i,n;
string a[100];
while(cin>>n)
{
int max_len=0;
for(i=0; i<n; i++)
{
cin>>a[i];
int sz=a[i].size();
max_len=max(max_len,sz);
}
radixSort(a,n,max_len);
for(i=0; i<n; i++)
cout<<a[i]<<endl;
}
return 0;
}
/*
8
qd ab qwe hhh a cws hhd hhz
*/
图片来自:程序员小灰