時間複雑度から多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)}のソート法
  • 2、混合ソート方法
  • 二、アルゴリズム適用の場合

  • ハイブリッドソート方式
    一、主な考え方
    現在、多くのソートアルゴリズムの中で、最も速いアルゴリズムの時間複雑度はO(n l o g n)O(nlogn)O(nlogn)であり、より効率的なアルゴリズムを実現できるだろうか.本稿では、時間的複雑度がO(n l o g n)O(nlogn)O(nlogn)O(nlogn)までのアルゴリズムを探すが、このアルゴリズムは独自の新しいアルゴリズムではなく、2つの異なるアルゴリズムをその優位性を混合したものであるため、「混合ソートアルゴリズム」と呼ぶ.
    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[n]arr[n]arr[n]に対して、
  • 配列a r arr arrを遍歴し、a r r arr arrにおける最大値m a x a maxaと最小値m i n a 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 arr arrを2回目に巡回し、現在の配列要素a r[i]arr[i]arr[i]arr[i]に対応するs o r t[a r[i]−m i n a]sort[arr[i]−mina]sort[arr[i]−mina]に1を加える.
  • 配列s o r t sort sortを巡回する、全ての非ゼロ要素s o r t[i]sort[i]sort[i]sort[i]に対応する数m i n a+i mina+i mina+i mina+iを印刷するとともに、s o r t[i]sort[i]sort[i]sort[i]を1 1ずつ減算.s o r t[i]sort[i]sort[i]sort[i]sort[i]がゼロの場合、次の要素が処理する.

  • 対応するC++コードは
    vector newSort(vector &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 sort(maxa - mina + 1);
        for(int i : arr) 
            sort[i - mina]++;
        //  4
        vector 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;
    }
    

    通常、m a x−a−m i n a+1>n maxa−mina+1>n maxa−mina+1>nであるが、a r arr arr中のほとんどの元素が同時にm a x−a−m i n a+1現在の他のアルゴリズム(ヒルソートを除く)では、最も速いのはスタックソート、高速ソートと集計ソートであり、時間複雑度はいずれもO(nl 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(logn)、O(n)である.ヒルソートの最適時間複雑度はまだ証明中であるため、本文はしばらく考慮しない.
    m a x a−m i n an l o g n maxa-mina>nlogn maxa-mina>nlognの場合、集計/高速ソートがより好ましい.両者を組み合わせると,O(n l o g n)O(nlogn)O(nlogn)O(nlogn)を常に超えない時間複雑度のアルゴリズムが得られるだろうか.
    2、混合ソート方法
    以上より、両者の性能を兼ね備えたハイブリッドソートアルゴリズムを試みることができる.
    与えられた配列a r[n]arr[n]arr[n]に対して、
  • 配列a r arr arrを遍歴し、a r r arr arrにおける最大値m a x a maxaと最小値m i n a minaを得る.
  • m a x a−m i n a maxa−mina−minaとn l o g n nlogn nlognの大きさを比較し、m a x a−m i n an l o g n maxa-mina>nlogn maxa-mina>nlognになると4に移る.
  • n e w S o r t()newSort()newSort()を使用してソートする.
  • は集計/高速/スタックソートアルゴリズムを用いてソートする.

  • ハイブリッドソートアルゴリズムC++コード(ここではステップ4でクイックソートを例に挙げる)
    //    newSort()
    vector newSort(vector &arr, int mina, int maxa){  
        vector sort(maxa - mina + 1);
        for(int i : arr) 
            sort[i - mina]++;
        
        vector 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 &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 quickSort(vector &arr, int low, int high){
        if(low < high) {
            int pos = part(arr, low, high);//  
            quickSort(arr, low, pos - 1);
            quickSort(arr, pos + 1, high);
        }
        return arr;
    }
    
    //    
    vector mixSort(vector &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);
        return quickSort(arr, 0, n - 1);//  
    }
    
    //    
    int main(){
        vector 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−a−m a−m i n a)O(logn)orO(maxa−mina)O(lognn(lognn)O(lognn)O(lognn(maxa−mina)O(lognn(lognn)O(lognn(lognn)O(maxa−min) or O(maxa-mina).
    二、アルゴリズム適用の場合
    本アルゴリズムは,m a x a−m i n a maxa−mina−maxa−minaを可能な限り小さいデータセット,すなわち,ある区間にデータ分布が集中するデータセット,e g:{1,5,3,3,2,4}eg:{1,5,3,2,4}eg:{1,5,3,2,4},{1,3,4,3,3,5}{1,3,4,3,3,3,3,3,5}{1,3,3,4,3,3,4,3,3,3,5}{5,3,4,3,3,3,3,3,3,3,3,3,3,5}eg本アルゴリズムの性能は優れている.
                                                                                                                                                                                     Y J Y                                                                                                                                                                F e b .   2 0 t h   ,   2021\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\YJY\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Feb.\20^{th}\,\2021                                                                                                                                                                                YJY                                                                                                                                                            Feb. 20th , 2021