更多排序算法參見:“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
*/
圖片來自:程序員小灰