尝试一种时间复杂度至多 O(nlogn) 的数组排序

一种混合排序方式

一、主要思路

目前众多排序算法中,最快的算法时间复杂度为 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(maxamina), O(n)} 的排序法

首先来看一种特定情形下表现优良的算法 .对于给定数组 a r r [ n ] arr[n] arr[n]

  1. 遍历数组 a r r arr arr ,获得 a r r arr arr 中最大值 m a x a maxa maxa 与最小值 m i n a mina mina

  2. 分配一个大小为 m a x a − m i n a + 1 maxa - mina + 1 maxamina+1 的数组 s o r t sort sort ,元素初值均置为 0 0 0

  3. 第二次遍历数组 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 中出现的次数;

  4. 遍历数组 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 maxamina+1>n ,但当 a r r arr arr 中大多数元素相同时,有 m a x a − m i n a + 1 < n maxa - mina + 1 < n maxamina+1<n ,所以该算法对应的时间复杂度为 m a x { O ( m a x a − m i n a ) ,   O ( n ) } max\{O(maxa - mina),\ O(n)\} max{O(maxamina), O(n)} ,空间复杂度为 O ( m a x a − m i n a ) O(maxa - mina) O(maxamina) . 这种算法适合于数据分布集中型的数组,数据越集中于某一区间, m a x a − m i n a + 1 maxa - mina + 1 maxamina+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 maxamina<nlogn 时,本算法时间复杂度优于归并/快速排序算法;但当 m a x a − m i n a > n l o g n maxa - mina >nlogn maxamina>nlogn 时,归并/快速排序更优 . 若将两者结合,是否可以得到一个时间复杂度始终不超过 O ( n l o g n ) O(nlogn) O(nlogn) 的算法呢?

2、混合排序方法

综上所述,可以尝试一种兼具两者性能的混合型排序算法:

对于给定数组 a r r [ n ] arr[n] arr[n]

  1. 遍历数组 a r r arr arr ,获得 a r r arr arr 中最大值 m a x a maxa maxa 与最小值 m i n a mina mina

  2. 比较 m a x a − m i n a maxa - mina maxamina n l o g n nlogn nlogn 大小,

    m a x a − m i n a < n l o g n maxa - mina < nlogn maxamina<nlogn 时,转到3 ;

    m a x a − m i n a > n l o g n maxa - mina >nlogn maxamina>nlogn 时,转到4 .

  3. 使用 n e w S o r t ( ) newSort() newSort() 进行排序;

  4. 使用归并/快速/堆排序算法排序 .

混合排序算法 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(maxamina), 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(maxamina) .

二、算法适用场合

本算法适用于使 m a x a − m i n a maxa - mina maxamina 尽可能小的数据集,即数据分布集中于某个区间的数据集, 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},并且单位区间内数据越密集,本算法性能越优良 .

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值