最も一般的なソート - クイックソート

クイックソートは、1960年にCARホーアによって提案されました。基本的な考え方は次のとおりです。二つの部分のための2つの独立した部分、すべてのデータの他の部分よりも、すべてのデータが小さくなるように一部、データのこの方法に分類されるデータを順序付けることによって、トリップ別途速いですソート、プロセス全体をソートすると、順序付けられたシーケンスにデータ全体を達成するために、再帰的にすることができます。キーとしてデータ(第1の数は、通常、アレイを選択される)、及びそれのすべてが中に配置されている数よりも少ない第一のデータのいずれかを選択し、配列A [0] ... A [N-1]をソートするために設けられています。左、その数字よりも、すべての大きい方がその右に、クイックソートへの旅として知られているプロセスに入れています。つまり、複数の値の同一の相対位置は、アルゴリズムの終了時に変動することが、クイックソートは安定ソートアルゴリズムではない、ことは注目に値します。

トリップ(パーティション)高速ソートアルゴリズムは、1)i、jは、並べ替えたとき始まる2つの変数を設定した:i = 0、J = N-1; 2)キーデータとして最初の配列要素に、割り当てをキーに、すなわち、キーは= [0]; 3)すなわち、正面(J)から検索の開始後、最初のキーよりも少ない[J]の値を見つけるために、Jから出発して前方に検索、[J ]及び[I]価値交換; 4)iが始まる後方探索から、すなわち逆方向検索(iは++)の開始前に、[I]を見つけるための最初のキーよりも大きい、[i]と[ I = Jまで5)を繰り返し、ステップ3と4; j]の値の交換(3,4-ステップ、修飾値を見つけられませんでした、即ち3 [j]は[I 4、キー以上であります]キーの変更がJよりも大きくないとき、iの値ようにJ = J-1、I = I + 1、あなたは資格の価値を、見つけ見つけるまでとき、私引き換え、Jポインタの位置変わらない。さらに、このプロセスはまさに私がJ-+または完了しなければならないとき、サイクルのこの時点で終了)するように私は、jは==します。

バブルソートに言うことができる、我々は最初の本当のソートアルゴリズムを学ぶことで、スペースの無駄のバケットソートの問題を解決するが、アルゴリズムの実行効率で多くのことを犠牲にしている、それが複雑に達する時間ですOを(N2) 。私たちはあたりのコンピュータを実行することができた場合は10万回、その後1種の李番号、バケットソートのみ必要0.1バブルソートが必要になりながら、秒に達し、千万秒115の長い日は、そうではありません怖いです。そこにスペースの無駄もないし、少し速くソートアルゴリズムそれできること?それは、「クイックソート」、それです!ただ非常にハイエンドがそれを感じていない、この名前を聞きます。

私たちは今、「仮定61279345108は」ソート10の数です。まず、単に参照番号としてこのシーケンスの番号を見つけるために、(おびえ用語はあなたはそれがZuoshaに使用される知っている数を意味するために使用されることはありません)。便宜のために、最初の番号せ6バールの参照番号などを。次に、配置するのに必要なすべての基準数よりも大きいシーケンス番号6の右側には、上の参照カウントよりも小さくなっている6本配置と同様、左側に、。

3 1 2 3 5 4 6 9 7 10 8

初期状態で、数6最初のシーケンス内の1ビット。私たちの目標は、にある6本の位置があると仮定して、シーケンスの途中でどこかに移動し、K今、我々は見つける必要kは、第一とk個の左から、ビット境界点以下である6、以上の適切な数有している6それについて考え、あなたがそれを行うことができる方法があるのですか?

あなたにそれのヒントを与えます。各番号はホーミングするようにそのバブルソートを思い出して、どのようにステップバイ「スワップ」のステップです。この時点で、あなたはまた、「為替」によってそれぞれの目標を達成することができます。ステップバイステップは、正確にどのようにそれを交換するには?便利なだけ交換して時間を節約するには?見下すために急いではいけない、彼は紙の外観上の描画、ペンを取り出しました。私の高校は、私はバブルソートを感じた最初の学習バブルソートアルゴリズムは明らかにあまりにも不合理である時間の無駄、唯一の隣接する2つの数値を比較するたびに、です。だから私は道を考え、以降私は、これは、私に少し自己陶酔を許可してください(^ O ^)「クイックソート」であることに気づきました。

方法は簡単です:それぞれ、初期シーケンスから「61279345108は、プローブスタートを終了します」「」最初から右にするために、左未満見つけるために、6つの、その後から、数字をより大きい見つける6つのそれらを交換、その後、数字を。ここでは、2つの変数IJ、それぞれ、左端と右端の点列。我々は、これらの二つの変数のために良い名前「センチネルI」と「センチネルjを」演奏しました。最初は私は一番左の配列(すなわち、に歩哨のポイントを聞かせてI = 1)、小数点数6センチネルましょうJの右端の配列に点(すなわち、J = 10)、デジタル点8

picture3.1

まずセンチネルjは行動を取るようになりました。ここで設定した参照番号は左端の番号ですので、あなたは歩哨のようにする必要がありjは最初に出て、(その理由について考えてください)非常に重要です。センチネルJの左にステップバイステップで移動する(すなわちJ - )、あなたがより少ない見つけるまで6停止する数字を。次センチネル私は右へ段階的に移動する(すなわち、I ++は、それがより大きな数見つかるまで、)6つの停止する数字。最後にセンチネルjはデジタルで停止5フロント、Sentinelは、私はデジタルで停止7前。

picture3.2

picture3.3

今センチネル交換IとセンチネルJの値は、要素を指摘しました。次の順序の交換をした後。

6 1 2 5 9 3 4 7 10 8

picture3.4

picture3.5

これ、初めて交換が完了しています。そして、センチネル開始jは(フレンドリーリマインダー再び、それぞれが歩哨にする必要があり、左に移動し続けるJ出発前)。彼が発見した4(以下、ベースライン6の要件を満たすために、より小さな後)に停止。センチネル私はまた、さらに右に移動するには、彼が見つかりました。9(よりもベースラインを6要件を満たすため、より大きな後)に停止しました。再びこの交換では、次の順序の交換後。

6 1 2 5 4 3 9 7 10 8

継続するために第2の交流、「プローブ」の終わり。センチネルjは左に移動していき、彼が見つかりました。3(参照番号より6が小さくなって、要件を満たすために)以降および停止しました。センチネル私は善、私、右に移動し続けます!この時、Sentinelは、とセンチネルjは、センチネルに会ったIおよびセンチネルjは達している3フロントを。この時、「検出」最後に説明。私たちは、数参照する63が交換されています。次の順序の交換をした後。

3 1 2 3 5 4 6 9 7 10 8

picture3.6

picture3.7

picture3.8

「プローブ」のこの最初のラウンドは本当に終わりました。このとき、参照番号6はカットオフ点である6つの番号は以下の左に等しい66右数以上である6ただ、プロセスを見て、実際にはセンチネルJの使命は、参照カウント未満を見つけることです、そしてセンチネルの使命は、参照カウントがされるまで、より大きい見つけることですIJの出会い、これまで。

OK、解釈が完了しています。今や参照番号6がホーミングされている、それだけの最初のシーケンスである6ビット。この時点で、我々は元の配列を有する6境界点は、二つの配列に分割として、配列は、「左31254は」、右列は「97108」。次に、また、我々は、これら二つの配列に対処する必要があります。そのため6列の左と右のは現在も非常に紛らわしいです。しかし、それは問題ではありません、私たちはちょうど限り、次の方法で処理したとしてシミュレートし、方法を習得してきた6つの左右のシーケンスを。今のところ処理するための6つの今それを左に列を。

左边的序列是“3 1 2 5 4”。请将这个序列以 3 为基准数进行调整,使得 3 左边的数都小于等于 33 右边的数都大于等于 3。好了开始动笔吧。

如果你模拟的没有错,调整完毕之后的序列的顺序应该是。

2 1 3 5 4

OK,现在 3 已经归位。接下来需要处理 3 左边的序列“ 2 1 ”和右边的序列“5 4”。对序列“ 2 1 ”以 2 为基准数进行调整,处理完毕之后的序列为“1 2”,到此 2 已经归位。序列“1”只有一个数,也不需要进行任何处理。至此我们对序列“ 2 1 ”已全部处理完毕,得到序列是“1 2”。序列“5 4”的处理也仿照此方法,最后得到的序列如下。

1 2 3 4 5 6 9 7 10 8

对于序列“9 7 10 8”也模拟刚才的过程,直到不可拆分出新的子序列为止。最终将会得到这样的序列,如下。

1 2 3 4 5 6 7 8 9 10

到此,排序完全结束。细心的同学可能已经发现,快速排序的每一轮处理其实就是将这一轮的基准数归位,直到所有的数都归位为止,排序就结束了。下面上个霸气的图来描述下整个算法的处理过程。

picture3.9

快速排序之所比较快,因为相比冒泡排序,每次交换是跳跃式的。每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样每次只能在相邻的数之间进行交换,交换的距离就大的多了。因此总的比较和交换次数就少了,速度自然就提高了。当然在最坏的情况下,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和冒泡排序是一样的都是 O(N2),它的平均时间复杂度为 O(NlogN)。其实快速排序是基于一种叫做“二分”的思想。我们后面还会遇到“二分”思想,到时候再聊。先上代码,如下。


    #include <stdio.h>
    int a[101],n;//定义全局变量,这两个变量需要在子函数中使用
    void quicksort(int left,int right)
    {
    int i,j,t,temp;
    if(left>right)
       return;

    temp=a[left]; //temp中存的就是基准数
    i=left;
    j=right;
    while(i!=j)
    {
       //顺序很重要,要先从右边开始找
       while(a[j]>=temp && i<j)
    j--;
       //再找右边的
       while(a[i]<=temp && i<j)
    i++;
       //交换两个数在数组中的位置
       if(i<j)
       {
    t=a[i];
    a[i]=a[j];
    a[j]=t;
       }
    }
    //最终将基准数归位
    a[left]=a[i];
    a[i]=temp;

    quicksort(left,i-1);//继续处理左边的,这里是一个递归的过程
    quicksort(i+1,right);//继续处理右边的 ,这里是一个递归的过程
    }
    int main()
    {
    int i,j,t;
    //读入数据
    scanf("%d",&n);
    for(i=1;i<=n;i++)
       scanf("%d",&a[i]);
    quicksort(1,n); //快速排序调用

    //输出排序后的结果
    for(i=1;i<=n;i++)
    printf("%d ",a[i]);
    getchar();getchar();
    return 0;
    }

可以输入以下数据进行验证

1061279345108

运行结果是

12345678910

下面是程序执行过程中数组 a 的变化过程,带下划线的数表示的已归位的基准数。


    1 2 7 9 3 4 5 10 8
    1 2 5 4 6 9 7 10 8
    1 3 5 4 6 9 7 10 8
    2 3 5 4 6 9 7 10 8
    2 3 5 4 6 9 7 10 8
    2 3 4 5 6 9 7 10 8
    2 3 4 5 6 9 7 10 8
    2 3 4 5 6 8 7 9 10
    2 3 4 5 6 7 8 9 10
    2 3 4 5 6 7 8 9 10
    2 3 4 5 6 7 8 9 10

1960年にクイックソート、CARホーア(アントニー・ホーア、チャールズ・アントニーリチャード・ホエア)によって提案され、その後、さらなる最適化を行うために多くの人々があります。興味のある方は、1962年にクイックソートアントニー・ホーアコンピュータジャーナルを行くと見ることができる紙「クイックソート」と「アルゴリズムの概要」第VII章を発表しました。高速ソートアルゴリズム明らかにするために、初めてコンピュータ分野で唯一のアントニー・ホーアされ、以降、彼は彼女と再利用のボスだった、同社は、彼は新しいマシンのための新しい高レベルの言語を設計したかったです。あなたは、これらはまだ先進的なものPASCAL、またはC言語を持っていた知っています。その後、アントニー・ホーアがEdsger Wybeダイクストラが参加(1972年チューリング賞を受賞し、私たちの後ろにこの偉大な神は、時間、その後、世間話を発生します)「ALGOL 60」トレーニングコースを組織し、彼はそのは行かないことを確認感じました新しい言語を設計し、それは新しいマシンの会社で使用することができるように、既存の「ALGOL 60」は、改善するほど良好ではありません。そこで彼は、「ALGOL 60は、」リリースのサブセットであるように設計しました。一度このバージョンの意志プレミア国際学術注意することにより、効率性と信頼性、アントニー・ホーアの実装で「ALGOL 60」のさまざまなバージョン。彼は後に「ALGOL X」のデザインも、よく知られた「ケース」ステートメントを発明したが、後に広くように、このようなPASCAL、C、Java言語など様々な高レベルの言語を採用して。もちろん、アントニー・ホーアコンピュータの分野で貢献し、多くの、彼は1980年にチューリング賞を受賞しました。


http://wiki.jikexueyuan.com/project/easy-learn-algorithm/fast-sort.html

おすすめ

転載: www.cnblogs.com/bqwzx/p/11028976.html
おすすめ