尝试探寻一种高效的数组排序
一种混合排序方式
一、主要思路
目前众多排序算法中,最快的算法时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn) ,能否实现一种更高效的算法呢?本文尝试寻找一种时间复杂度至多为 O ( n l o g n ) O(nlogn) O(nlogn) 的算法,该算法并不是自成一套的全新算法,而是将两种不同的算法取其优势混合而成,故称 “ 混合排序算法 ” .
1、时间复杂度 m a x { O ( m a x a − m i n a ) , O ( n ) } max\{O(maxa - mina),\ O(n)\} max{O(maxa−mina), O(n)} 的排序法
首先来看一种特定情形下表现优良的算法 .对于给定数组 a r r [ n ] arr[n] arr[n],
-
遍历数组 a r r arr arr ,获得 a r r arr arr 中最大值 m a x a maxa maxa 与最小值 m i n a mina mina ;
-
分配一个大小为 m a x a − m i n a + 1 maxa - mina + 1 maxa−mina+1 的数组 s o r t sort sort ,元素初值均置为 0 0 0 ;
-
第二次遍历数组 a r r arr arr ,将当前数组元素 a r r [ i ] arr[i] arr[i] 对应的 s o r t [ a r r [ i ] − m i n a ] sort[arr[i] - mina] sort[arr[i]−mina] 加 1 1 1 ,即 s o r t [ i ] sort[i] sort[i] 的含义为元素 i + m i n a i + mina i+mina 在 a r r arr arr 中出现的次数;
-
遍历数组 s o r t sort sort ,将所有非零元素 s o r t [ i ] sort[i] sort[i] 对应的数 m i n a + i mina + i mina+i 打印,同时 s o r t [ i ] sort[i] sort[i] 减 1 1 1 .
当 s o r t [ i ] sort[i] sort[i] 为零时,处理下一个元素 .
相应 C++ 代码为
#include <vector>
//没学过STL容器vector的同学可以理解为vector<int> a(n)就是int a[n] = {0};
vector<int> newSort(vector<int> &arr){
//步骤1
int mina = arr[0], maxa = arr[0];
for(int i : arr) {
mina = mina > i ? i : mina;
maxa = maxa < i ? i : maxa;
}
//步骤2,3
vector<int> sort(maxa - mina + 1);
for(int i : arr)
sort[i - mina]++;
//步骤4
vector<int> res(arr.size());
int index = 0;
for(int i = 0; i < maxa - mina + 1; i++){
if(sort[i]) {
res[index++] = mina + i;
sort[i--]--;
}
}
return res;
}
//测试用例
int main(){
vector<int> a = {6, 9, 4, 6, 8, 6, 7, 6, 5, 5, 9, 8,10};
a = newSort(a);
for(int i : a) cout << i << ' ';
return 0;
}
通常情况下 m a x a − m i n a + 1 > n maxa - mina + 1 > n maxa−mina+1>n ,但当 a r r arr arr 中大多数元素相同时,有 m a x a − m i n a + 1 < n maxa - mina + 1 < n maxa−mina+1<n ,所以该算法对应的时间复杂度为 m a x { O ( m a x a − m i n a ) , O ( n ) } max\{O(maxa - mina),\ O(n)\} max{O(maxa−mina), O(n)} ,空间复杂度为 O ( m a x a − m i n a ) O(maxa - mina) O(maxa−mina) . 这种算法适合于数据分布集中型的数组,数据越集中于某一区间, m a x a − m i n a + 1 maxa - mina + 1 maxa−mina+1 的值越小,时间复杂度也就越趋近 O ( n ) O(n) O(n) .
目前其他算法 ( 除去希尔排序 ) ,最快的是堆排序、快速排序与归并排序,时间复杂度均为 O ( n l o g n ) O(nlogn) O(nlogn) ,空间复杂度分别为 O ( 1 ) , O ( l o g n ) , O ( n ) O(1),\ O(logn),\ O(n) O(1), O(logn), O(n) . 由于希尔排序的最优时间复杂度仍在证明中,本文暂不做考虑 .
当 m a x a − m i n a < n l o g n maxa - mina < nlogn maxa−mina<nlogn 时,本算法时间复杂度优于归并/快速排序算法;但当 m a x a − m i n a > n l o g n maxa - mina >nlogn maxa−mina>nlogn 时,归并/快速排序更优 . 若将两者结合,是否可以得到一个时间复杂度始终不超过 O ( n l o g n ) O(nlogn) O(nlogn) 的算法呢?
2、混合排序方法
综上所述,可以尝试一种兼具两者性能的混合型排序算法:
对于给定数组 a r r [ n ] arr[n] arr[n],
-
遍历数组 a r r arr arr ,获得 a r r arr arr 中最大值 m a x a maxa maxa 与最小值 m i n a mina mina ;
-
比较 m a x a − m i n a maxa - mina maxa−mina 与 n l o g n nlogn nlogn 大小,
当 m a x a − m i n a < n l o g n maxa - mina < nlogn maxa−mina<nlogn 时,转到3 ;
当 m a x a − m i n a > n l o g n maxa - mina >nlogn maxa−mina>nlogn 时,转到4 .
-
使用 n e w S o r t ( ) newSort() newSort() 进行排序;
-
使用归并/快速/堆排序算法排序 .
混合排序算法 C++ 代码 ( 这里步骤4以快速排序为例)
#include <vector>
//稍加改动newSort()
vector<int> newSort(vector<int> &arr, int mina, int maxa){
vector<int> sort(maxa - mina + 1);
for(int i : arr)
sort[i - mina]++;
vector<int> res(arr.size());
int index = 0;
for(int i = 0; i < maxa - mina + 1; i++){
if(sort[i]) {
res[index++] = mina + i;
sort[i--]--;
}
}
return res;
}
//快速排序
//定义一个快排的划分函数part(),即一趟排序过程,将数组分为左右两部分,左边所有元素小于p,右边元素全部大于等于p
int part(vector<int> &arr, int low, int high){
int p = arr[low];
while(low < high) {
while(low < high && arr[high] >= p) high--;
arr[low] = arr[high];
while(low < high && arr[low] <= p) low++;
arr[high] = arr[low];
}
arr[low] = p; //这行容易被忽略
return low;
}
//采用递归快速排序
vector<int> quickSort(vector<int> &arr, int low, int high){
if(low < high) {
int pos = part(arr, low, high); //part()划分
quickSort(arr, low, pos - 1);
quickSort(arr, pos + 1, high);
}
return arr;
}
//混合排序
vector<int> mixSort(vector<int> &arr){
//步骤1
int mina = arr[0], maxa = arr[0];
int n = arr.size();
for(int i : arr) {
mina = mina > i ? i : mina;
maxa = maxa < i ? i : maxa;
}
//步骤2,3,4,这里取log以2为底;
if(maxa - mina + 1 < n * log(n) / log(2)) return newSort(arr, mina, maxa); //newSort排序
return quickSort(arr, 0, n - 1); //快速排序
}
//测试用例
int main(){
vector<int> a = {6, 9, 4, 2, 8, 6, 7, 3, 2, 5, 1};
a = mixSort(a);
for(int i : a) cout << i << ' ';
return 0;
}
算法时间复杂度 m i n { O ( n l o g n ) , m a x { O ( m a x a − m i n a ) , O ( n ) } } min\{O(nlogn),\ max\{O(maxa-mina),\ O(n)\}\} min{O(nlogn), max{O(maxa−mina), O(n)}} ,空间复杂度为 O ( l o g n ) o r O ( m a x a − m i n a ) O(logn)\ or\ O(maxa-mina) O(logn) or O(maxa−mina) .
二、算法适用场合
本算法适用于使 m a x a − m i n a maxa - mina maxa−mina 尽可能小的数据集,即数据分布集中于某个区间的数据集, e g : { 1 , 5 , 3 , 2 , 4 } eg: \{1,5,3,2,4\} eg:{1,5,3,2,4} , { 1 , 3 , 3 , 4 , 3 , 3 , 5 } \ \{1,3,3,4,3,3,5\} {1,3,3,4,3,3,5},并且单位区间内数据越密集,本算法性能越优良 .