インタビューでは、多くの場合、ソートアルゴリズムをテスト

ディレクトリ

 

予備

バブルソート

アルゴリズム

 分析バブルソート

最適化のバブルソート

選択ソート 

アルゴリズム

並べ替え分析を選択 

ヒープソート

アルゴリズム

ヒープソートの分析

直接挿入ソート

アルゴリズム

挿入ソートの分析 

シェルソート

アルゴリズム

分析のシェルソート

クイックソート

アルゴリズム

クイックソートの分析

クイックソートの最適化

非再帰的クイックソート


予備

同等のソート済みオブジェクトのタイプに属し、(参照)代入演算子を除き、互換COMPARATO法を用いて入力データをソートするために適用することができ、これは、入力データの動作のみです。これらの条件下でのソートが呼び出され、比較の並べ替えに基づきます。

並び替え安定性:293513 '10は、完全なソート1233'で、その後安定している5910、ソートは不安定なものですその後、完全12335910」です。決意の方法があるソート交換ジャンプが発生しない安定しました。安定したソートソート不安定になることができ、不安定な秩序は安定ソートになることはできません。

ソートソート内部および外部、内部ソートの比較的小さい(数百万未満)内の要素の数のメモリで注文されています。外部ソートは、ソートに、ディスク上の要素の特定の数が多い順にソートされます。この記事では、内部ソートの前の7種類に属し、最後の一つは、外部ソートです。

バブルソート

アルゴリズム

2つのサイクルのために、ループの最初の回数である私は、ループjの比較の第二の数です。隣接要素が比較され、条件が交換されます。Pの数を比較した後、p個のデータを注文することになります。

元の配列 8 6 3 9 4 7 比較の数
最初の旅行の後 6 3 8 4 7 9 5
第二の旅の後 3 6 4 7 8 9 4
第三の旅の後 3 4 6 7 8 9 3
第四の旅の後 3 4 6 7 8 9 2
第五の旅の後 3 4 6 7 8 9 1
    public static void bubbleSort(int[] array) {
        for (int i = 0; i < array.length-1 ; i++) {
            for (int j = 0; j < array.length-1-i; j++) {
                if (array[j] > array[j+1]) {
                    int tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                }
            }
        }
    }

 分析バブルソート

2サイクルのために、O(N)の時間複雑。
余分なスペースの用途ない、空間計算量:O(1)
安定性:安定

最適化のバブルソート

私たちは、第三の旅を注文された場合には、上記の例を見つけるでしょう、したがって比較する必要はありません。コードが知っているどのように秩序交換が順番に説明されていないのであれば、それは、比較の過程にあります。最適化を次のように私たちは、ブール変数を定義することができます。

public static void bubbleSort(int[] array) {
    boolean flg = false;
    for (int i = 0; i < array.length-1; i++) {
        for (int j = 0; j < array.length-1-i; j++) {
            if (array[j] > array[j+1]) {
                int tmp = array[j];
                array[j] = array[j+1];
                array[j+1] = tmp;
                flg = true;
            }
        }
        if (!flg) {
            break;
        }
    }
}

選択ソート 

アルゴリズム

私は数字0から、必要に応じてより小さく、続いて、そのスイッチング素子。ソートへの旅は、オーダーの最初の要素で行われます。

    public static void selectSort(int[] array) {
        for (int i = 0; i < array.length; i++) {
            for (int j = i+1; j < array.length; j++) {
                if (array[i] > array[j]) {
                    int tmp = array[i];
                    array[i] = array[j];
                    array[j] = tmp;
                }
            }
        }
    }

並べ替え分析を選択 

時間の複雑さ:O(N ^ 2)[最高と最悪です]
スペースの複雑さ:O(1)
安定性:不安定

ヒープソート

アルゴリズム

方法をトラバースすることによって配列を作成するために、スタックアレイ。昇順に、大きなルートヒープに調整します。そして、最上位の要素が発注され、最大の要素です。小根ヒープに調整するために、降順に、次に一番上の要素が順序付けされる場合、最小の要素です。

具体的には:
1.(昇順で)大根ヒープを調整します。これは、各サブツリーを下方に調整されるトップダウンからの調整、大根ヒープであることを保証することです。父親のノードについて、方法を調整し、最大の子を比較するには、子どもたちが権利を持っていることを確実にするために、それは子供+ 1が小さい長さより決定することで、(右の子がある場合)。子ノードが父のノードよりも大きい場合は、次の2つを交換することができます。それはちょうどルートをできるように-1を調整し続けなければならない調整する[A]ちょうど二の調整です。
2.種類は、最初の要素と最後の要素は、オーダーの最後の要素を交換します。0ツリーの下で被写体を調整大ルートヒープです。定義された端、end--を切り替えるたびに、下方に調整します。端= 0説明調整が完了したとき。

 //向下调整
    public static void adjustDown(int[] array, int root, int len) {
        int parent = root;
        int child = 2*parent+1;
        while (child < len) {
            if (child+1 < len && array[child] < array[child+1]) {
                child++;
            }
            //此时child就是指向子孩子的较大值
            if (array[child] > array[parent]) {
                int tmp = array[child];
                array[child] = array[parent];
                array[parent] = tmp;
                //调整子树也要是大根堆
                parent = child;
                child = 2*parent+1;
            } else {
                break;
            }
        }
    }

    //每棵树都向下调整
    public static void creatHeap(int[] array) {
        for (int i = (array.length-1-1)/2; i >= 0; i--) {
            adjustDown(array, i, array.length);
        }
    }

    //进行排序
    public static void heapSort(int[] array) {
        creatHeap(array);
        int end = array.length-1;
        while (end > 0) {
            int tmp = array[0];
            array[0] = array[end];
            array[end] = tmp;
            //adjustDown取不到len 所以先调整后end--
            adjustDown(array, 0, end);
            end--;
        }
    }

    public static void main(String[] args) {
        int[] array = new int[]{27, 15, 19, 18, 28, 34, 65, 49, 25, 37};
        heapSort(array);
        System.out.println(Arrays.toString(array));
    }

ヒープソートの分析

葉ノードとルートノードの数は約1であるので:時間複雑1、ルートノードがN / 2から選択され、ルートノードの各々は、下方log2Nを調整しなければなりません。すなわちソートO(N)と結合log2N(底2)* N / 2 + O(N)である== Nlog2N

宇宙複雑:O(1)

最悪、最高、平均複雑さがNlog2Nです

時間の複雑さの内蔵ヒープ:Nlog2N

調整時間の複雑さ:log2N

安定性:不安定

 

直接挿入ソート

アルゴリズム

ソート時間がN-1の組成を有するソーティング、P = N-1、P = 1の場合、0-Pの位置を確保するために挿入ソートの要素は、状態をソート。並び替え、次のとおりです。

元の配列 34 8 64 51 32 21
ランP = 1の後 8 34 64 51 32 21
ランのp = 2の後 8 34 64 51 32 21
そして、P = 3回 8 34 51 64 32 21
P後= 4回 8 32 34 51 64 21
後のP = 5回 21 32 34 51 64

この種のアプローチは、我々はポーカーに似て公開することができます。最初のデータは、iは1から開始する必要があり、注文されています。TMPへのデータI添字番号。前述の標準の要素番号の比較Iは、添え字jは、I = 1。添字j個の要素は、TMPおよび比較します。jは要素の数よりも大きい場合、jは上記のどの要素がないことを示す、0以上である場合,,インデックス、添字J + 1に素子番号jのインデックス、jはtmpです。TMPは、位置j + 1にデータを置きます。この旅行は、クイックソートです。TMPは、要素jの数よりも大きい場合、記述が既にJ + 1にTMPに直接注文されていることに留意されたいです。

    public static void insertSort(int[] array) {
        int j = 0;
        for (int i = 1; i < array.length; i++) {
            int tmp = array[i];
            for (j = i-1; j >= 0; j--) {
                if (tmp < array[j]) {
                    array[j+1] = array[j];
                } else {
                    break;
                }
            }
            array[j+1] = tmp;
        }
    }

挿入ソートの分析 

二つのループにある入力データが順序付けされた場合に最良の時間複雑度はO(N)、最悪の場合はO(N ^ 2)であり、すなわち、であるので、内部ループの試験は常に、決意が満たされていない直ちに終了されます無秩序時間。そして、より多くのより高速なデータを命じました。

アプリケーションの余分なスペースなので、空間計算量はO(1)であります

IF(TMP <=配列[J])の不安定性の種のための条件は、IF(TMP <配列[J])ソートなるとソートは、安定しています。

シェルソート

アルゴリズム

最適化されたソートに直接ソートヒル。パケットの順序は、より速く、より直接的な挿入ソートを命じました。インクリメンタルは互いに素でなければならない、最後の増分は1でなければなりません。私たちは、データがよりよい順序を持つように、パケットは(昇順の場合)前の比較的大きな、比較的小規模なデータの後ろにデータをスキップします、パケットジャンプパケットを使用することができます。

    public static void shell(int[] array, int gap) {
        for (int i = gap; i < array.length; i++) {
            int tmp = array[i];
            int j = 0;
            for (j = i-gap; j >= 0; j -= gap) {
                if (array[j] > tmp) {
                    array[j+gap] = array[j];
                } else {
                    break;
                }
            }
            array[j+gap] = tmp;
        }
    }

    public static void shellSort(int[] array) {
        //分的组数
        int[] drr = {5,3,1};
        for (int i = 0; i < drr.length; i++) {
            shell(array, drr[i]);
        }
    }

 

プラクティスはますます整然としたデータのパケットの変化で、5,3,1をグループ分けしました。 

分析のシェルソート

時間の複雑さ:O(N ^ 1.3 - N ^ 1.5)

宇宙複雑:O(1)

安定性:不安定

クイックソート

アルゴリズム

参照を取得:0は、インデックス番号のための低屈折率、高長-1として定義されます。TMPは、バック検索データ要素、高い数に目標の位置にフロントよりも大きい、低い位置番号に、背面からよりも小さいTMPデータ要素を見つけるために、TMPに被写体の要素の数が少ないです。低および高は彼らに、TMPに会ったとき。この場所は、基準位置です。小型基地、大規模なベンチマークよりも右のベースラインより左のベースライン。ピボット[旅]クイックソート - 「範囲[低、高]、再帰検索他のベンチマークを与えます!

 

    public static int partion(int[] array, int start, int end) {
        int tmp = array[start];
        while (start < end) {
            while ((start < end) && array[end] >= tmp) {  //9 3 2 9 10
             end--;
            }
            if (start >= end) {
               array[start] = tmp;
               break;
            } else {
                array[start] = array[end];
            }

            while ((start < end) && array[start] <= tmp) {  //9 3 2 9 10
               start++;
            }
            if (start >= end) {
                array[start] = tmp; //
                break;
            } else {
                array[end] = array[start];
            }

        }
        return start;
    }

    public static void quick(int[] array, int low, int high) {
        //递归的终止条件:只有一个元素
        if (low >= high) { //=zuo  >you
            return;
        }
        //1.写一个函数把待排序序列分为两部分
        int pivot = partion(array, low, high); //low和high是局部变量
        //开始递归 左右
        quick(array, low, pivot-1);
        quick(array, pivot+1, high);
    }

    public static void quickSort(int[] array) {
        quick(array, 0, array.length-1);
    }

クイックソートの分析

時間複雑:O(nlog2n)

最高の時間の複雑さ:

最悪時間計算:[データが順序付け]はO(n ^ 2)

宇宙複雑:O(log2n)[左側のツリーの高さ]

安定性:不安定

クイックソートの最適化

最適化1:

プロセスは、クイックソート、データのより多くの注文になってきてすることができる場合は、直接挿入ソートのために、より多くのより高速なデータを命じました。O(N) - "N-" 小さいです。ソート処理は、セクションのデータ量が小さい場合、閾値 - 「100直接挿入ソート

public class QuickSortbetter1 {
    public static int partion(int[] array, int start, int end) {
        int tmp = array[start];
        while (start < end) {
            while ((start < end) && array[end] >= tmp) {  //9 3 2 9 10
                end--;
            }
            if (start >= end) {
                array[start] = tmp;
                break;
            } else {
                array[start] = array[end];
            }

            while ((start < end) && array[start] <= tmp) {  //9 3 2 9 10
                start++;
            }
            if (start >= end) {
                array[start] = tmp; //
                break;
            } else {
                array[end] = array[start];
            }

        }
        return start;
    }

    public static void insertSort2(int[] array, int low, int high) {
        int j = 0;
        for (int i = low+1; i <= high; i++) {
            int tmp = array[i];
            for (j = i-1; j >= low; j--) {
                if (array[j] > tmp) {
                    array[j+1] = array[j];
                } else {
                    break;
                }
            }
            array[j+1] = tmp;
        }
    }

    public static void quick(int[] array, int low, int high) {
        //递归的终止条件
        if (low >= high) {
            return;
        }

        if (high-low+1 < 100) {
            insertSort2(array, low, high);
            return;
        }
        //1.写一个函数把待排序序列分为两部分
        int pivot = partion(array, low, high); //low和high是局部变量
        //开始递归 左右
        quick(array, low, pivot-1);
        quick(array, pivot+1, high);
    }

    public static void quickSortBetter1(int[] array) {
        quick(array, 0, array.length-1);
    }

 

最適化2:

参照にバブルソートの劣化を見つける12345678910の場合

分割統治アルゴリズム - 「高速行は - 」最良の場合は均等に順序付けられたシーケンスを分割します。

3つのデジタルフランス9/4 = 2を取っ:あなたは12345678910均一なセグメンテーションをしたい場合。参考として途中で3桁の中央値を取ります

すなわち、ソート中央値であると、低および高シーケンスを取るための時間であり、配列[中間] <=配列[低] <=配列[高]。その結果は、三の低い中央値である要素の対象となります。

 

public class QuickSortBetter2 {
    public static int partion(int[] array, int start, int end) {
        int tmp = array[start];
        while (start < end) {
            while ((start < end) && array[end] >= tmp) {  //9 3 2 9 10
                end--;
            }
            if (start >= end) {
                array[start] = tmp;
                break;
            } else {
                array[start] = array[end];
            }

            while ((start < end) && array[start] <= tmp) {  //9 3 2 9 10
                start++;
            }
            if (start >= end) {
                array[start] = tmp; //
                break;
            } else {
                array[end] = array[start];
            }

        }
        return start;
    }

    public static void swap(int[] array, int low, int high) {
        int tmp = array[low];
        array[low] = array[high];
        array[high] = tmp;
    }

    public static void ThreeNumOfMiddle(int[] array, int low, int high) {
        //array[mid] <= array[low] <= array[high];
        int mid = (low+high)/2;
        if (array[mid] > array[high]) {
            swap(array, mid, high);
        }
        if (array[mid] > array[low]) {
            swap(array, mid, low);
        }
        if (array[low] > array[high]) {
            swap(array, low, high);
        }
    }


    public static void quick(int[] array, int low, int high) {
        //递归的终止条件
        if (low >= high) {
            return;
        }

        ThreeNumOfMiddle(array, low, high);
        //1.写一个函数把待排序序列分为两部分
        int pivot = partion(array, low, high); //low和high是局部变量
        //开始递归 左右
        quick(array, low, pivot-1);
        quick(array, pivot+1, high);
    }

    public static void quickSort(int[] array) {
        quick(array, 0, array.length-1);
    }

最適化3: 

同じ基底要素法を収集します。

非再帰的クイックソート

public static int partion(int[] array, int start, int end) {
    int tmp = array[start];
    while (start < end) {
        while ((start < end) && array[end] >= tmp) {  //9 3 2 9 10
            end--;
        }
        if (start >= end) {
            array[start] = tmp;
            break;
        } else {
            array[start] = array[end];
        }

        while ((start < end) && array[start] <= tmp) {  //9 3 2 9 10
            start++;
        }
        if (start >= end) {
            array[start] = tmp; //
            break;
        } else {
            array[end] = array[start];
        }

    }
    return start;
}

public static void quick(int[] array, int low, int high) {
  int pivot = partion(array, low, high);
  Stack<Integer> stack = new Stack<>();

  if (pivot > low+1) { //左边有两个元素可以入栈
      stack.push(low);
      stack.push(pivot-1);
  }
  if (pivot < high-1) { //右边有两个元素可以入栈
      stack.push(pivot+1);
      stack.push(high);
  }

  while (!stack.empty()) {
      high = stack.pop();
      low = stack.pop();
      pivot = partion(array, low, high);
      if (pivot > low+1) { //左边有两个元素可以入栈
          stack.push(low);
          stack.push(pivot-1);
      }
      if (pivot < high-1) { //右边有两个元素可以入栈
          stack.push(pivot+1);
          stack.push(high);
      }
  }

}

public static void quickSort(int[] array) {
    quick(array, 0, array.length-1);
}

 2019年の最後の日は、右ここで、願い事をします。私は2020年に、満足のいくプラン、赤、白アヒルをこの素晴らしい年に取得することを願っています!上に行くために、夢を。さようなら2019年、2020ふふふこんにちはO(∩_∩)O〜ヘクタール

 

 

 

 

 

 

 

 

公開された51元の記事 ウォン称賛14 ビュー2303

おすすめ

転載: blog.csdn.net/qq_41185460/article/details/104044153