䞊べ替えに぀いおバブル、クむック、コヌム...

この蚘事の䞻な目的は、初心者プログラマヌです。 䞀般的な䞊べ替えに぀いお、およびむンタヌネットの芋出しで蚀及されおいる蚘事の海に぀いお、なぜもう1぀必芁なのですか たずえば、ハブに関する良い蚘事がありたす バブル゜ヌトずすべおすべお 。 第䞀に、あたり良いものはありたせん。第二に、この蚘事では「なぜ、䜕、どのように、なぜ」ずいう質問に答えたいず思いたす。なぜ゜ヌトが必芁なのですか たず、デヌタの怜玢ず衚瀺甚。 未゜ヌトのデヌタを䜿甚するタスクには、解決が非垞に困難なものず、䞍可胜なものがありたす。 䟋単語がアルファベット順に゜ヌトされおいるスペルチェック蟞曞。 そうでない堎合は、正しい単語を芋぀けおください。 サブスクラむバヌがアルファベット順に゜ヌトされおいる電話垳。 䞊べ替えがオプションであり、あたり必芁ではない堎合でも、䞊べ替えられたデヌタを䜿甚するず䟿利です。



どのような皮類のデヌタを゜ヌトしたすか 比范ず亀換を䜿甚しお、配列内の敎数デヌタを゜ヌトしたす。 ぀たり 配列のm [i]ずm [j]i <jの芁玠を比范し、j番目がi番目より「小さい」堎合、それらを亀換したす。 結果ずしお、配列は昇順で゜ヌトされたす。

泚 比范するので、m [j] / 10 <m [i] / 10です。 これは、同じキヌを持぀アむテムがどのように゜ヌトされるかを確認するために行われたす。 この比范では、30 <40、ただし30 = 31 = 32 ...安定たたは安定した䞊べ替えは、同じ比范キヌを持぀芁玠の順序を倉曎したせんこの䟋では、比范キヌは/ 10芁玠の倀の敎数郚分です



以䞋は初期未゜ヌト配列です。
50 32 40 31 20 30 10
゜ヌト枈み
10 20 32 30 31 40 50
泚芁玠32、31、30の順序が倉曎されたした。 ゜ヌトは安定しおいたせん安定しおいたせん。



この蚘事で䜿甚されおいるすべおの䞊べ替えは、いく぀かの芁玠を比范し、それらが正しい順序になっおいない堎合は倉曎したす。 それらはどう違うのですか 比范する芁玠のペアを遞択する方法が異なりたす。

以䞋は、Cの゜ヌト手順の䟋です。 どこでも、最初のパラメヌタヌは配列のアドレス、2番目は配列内の芁玠の数です。 プロシヌゞャの倖偎のルヌプはパスず呌ばれ、内偎のルヌプは単玔にルヌプです。

簡単な仕分け

パスは配列のすべおの芁玠を反埩凊理し、ルヌプ内で珟圚の芁玠ず埌続のすべおの芁玠を比范したす。
void sorto(int *m,int n) // , , ...  { int tmp; for (int i=0;i<n-1;++i) { //  for (int j=i+1; j<n;++j) { //  if (m[j]/10<m[i]/10) { // j- ,     i- tmp=m[i]; m[i]=m[j]; m[j]=tmp; } } } }
      
      



䜜業結果
10 20 32 31 30 40 50
シンプルな䞊べ替えに加えお、実装が簡単で安定しおいたす。

短所-それは非垞に遅いので 倚くの比范操䜜がありたす。 n個の芁玠はそれぞれ埌続のすべおの芁玠ず比范されるため、比范の数は〜n * n / 2です。 n = 100000の堎合、比范は50億です。 確かに、n = 1000の堎合、「唯䞀」の比范は50䞇であり、最新のコンピュヌタヌは1秒未満でこれを行うこずができるため、少量でこの゜ヌトが適しおいたす.1぀の重芁なマむナスがある堎合-デヌタがほずんど゜ヌトされおいる堎合10䞇の芁玠のうち、10のみがアりトオブプレヌス、すべお同じように、動䜜時間はほずんど倉わりたせん、なぜなら 比范操䜜が倚くなりたす。アルゎリズムを改善しお、

バブル゜ヌト

「バブル」であり、「バブル」でもありたす。内偎のルヌプは配列を䜕床も繰り返し、珟圚の芁玠を前の芁玠ず比范したすしたがっお、実行は1から始たりたす。珟圚の芁玠が小さい堎合は、前の芁玠ず再配眮したす。 順列の堎所は倉数kに栌玍され、kのパッセヌゞの終わりにむンデックスがあり、そこから配列が゜ヌトされたす。
 void sortb(int *m,int n) { int tmp,k; while(n>1) { //  ,     k=0; //   for (int i=1; i<n;++i) { if(m[i]/10<m[i-1]/10) { tmp=m[i-1]; m[i-1]=m[i]; m[i]=tmp; k=i; //       } } n=k; //  k   } }
      
      



最悪の堎合元の配列が逆の順序で䞊べ替えられた堎合、同じn * n / 2の比范が埗られたす。最高の堎合ず良い堎合のどちらですか最良の堎合は、配列が完党に短瞮された堎合です。その埌、最初のパスで䜕も再配眮されたせんパッセヌゞの終わりにnに0k = 0が割り圓おられ、2回目のパスはありたせん。100,000パスの代わりに1぀だけです玠晎らしいですが、配列が䞊べ替えられおもたったく䞊べられない堎合はどうでしょう。たずえば、䞊べ替えられた配列の最小芁玠ず最倧芁玠を䞊べ替えお、問題のある「アレむ30- 32は同じキヌを持っおいたす
50 20 32 31 30 40 10
1パスの最初のステップでは、「20」が「50」ず比范され、亀換が行われたす。 次のステップでは、「32」が「50」ず再び比范されたす珟圚は「20」の䜍眮を占めおいたす。その結果、最初のパスの終わりに「50」が終わりに眮き換わり、残りはすべお1ポゞションを配列の先頭に移動したす。最初の䜍眮が䞊にあり、䞋の䜍眮が䞋にあるず想像するず、通過の結果ずしお最も重いものが䞋になり、最も軜いものになりたす。ある蚘事では、重い芁玠は「野りサギ」ず呌ばれ、軜い芁玠は「カメ」ず呌ばれたす。 オヌド「りサギ」は、より重芁なりサギバトンに乗っお走るに出䌚うか、その堎所に着くたで、最埌たでたたはdrれ走りたす。 、あなたはあなたの堎所に到達するためにnパスを必芁ずしたす。最も重い「ペレット」は1回のパスで玠早くownれ、最も軜い「バブル」はゆっくりずポップアップしたす。通路。 最軜量が配列の最埌にある堎合、配列内の芁玠ず同じ数のパスが必芁です。



圌らがそれほど干枉しないように、「カメ」をどうするか。 救助に来たす

シェヌカヌ゜ヌト

泡の遞別で重い芁玠がすぐに沈み、軜い芁玠がゆっくりず浮くのはなぜですか 比范サむクルは配列の先頭から末尟に移動し、重い芁玠を「ドラッグ」するためです。 そしお、最埌から最初に移動するず、肺がすぐに珟れ、重い肺がゆっくりず沈みたす。 1回のパスで最も軜いものが最埌から最初に移動したす。 偶数パスでのシェヌカヌの゜ヌトは、最初から最埌たで移動し、奇数セットでは、問題の配列は3パスで゜ヌトされたす。 ほが゜ヌトされたアレむの堎合、シェヌカヌの゜ヌトは「バブル」よりもはるかに高速ですが、ランダムに゜ヌトされた゜ヌスアレむの堎合、ゲむンは通垞それほど倧きくありたせん。

ヘアブラシを䞊べ替える

たたは櫛。 繰り返したすが、なぜバブルがゆっくりポップアップするのでしょうか 通過䞭に圌は1ポゞションに移動するためです。 そしお、なぜ圌は1ポゞションしか動かないのですか 隣接する芁玠が比范および再配眮されるためです。 それでは、隣接する芁玠ではなく、距離s各パスで埐々にsを枛らすにある芁玠を比范しおみたしょう。 このアむデアを実践に移すず、櫛で゜ヌトするこずになりたす。
 void sortc(int *m,int n) { int tmp,k; int s=n; //    long long cnt=0; while(n>1) { s/=1.247f; //    .      80%   , //         20% if (s<1) s=1; // 0   ,  1 k=0; //   for (int i=0; i+s<n;++i) { // ,    ( s  )   if(m[i]/10>m[i+s]/10) { tmp=m[i]; m[i]=m[i+s]; m[i+s]=tmp; k=i; } ++cnt; } if (s==1) //  1,    .   n=k+1; } }
      
      



アむデアは単玔なようで、アルゎリズムは耇雑ではありたせんが、結果は印象的です。 櫛の䞊べ替えは、バブル/シェヌカヌよりもはるかに高速であるこずが刀明し、「迅速な」qsort䞊べ替えを远い越すこずさえできたす。 しかしマむナスがありたす-それは安定しおいたせん盎感的に明らかです。

Qsortクむック゜ヌト

配列のクむック゜ヌト機胜は非垞に簡単です。
 //   qsort int fcomp(const void *i, const void *j) { return (*(int *)i)/10 - (*(int *)j)/10; } void sortq(int *m,int n) { qsort(m,n,sizeof(int),&fcomp); }
      
      



暙準のqsortクむック゜ヌトを䜿甚するため、単玔です。 䞎えられたアルゎリズムをもう䞀床芋おみたしょう。 党䜓で、芁玠のペアm [i]ずm [j]が遞択され、比范されたす。 しかし、m [i]ずは䜕ですか これは、敎数mの配列のi番目の芁玠、たたは「アドレスAi = m + i * <sizeofint>にある芁玠」です。 したがっお、j番目の芁玠はアドレスAj = m + j * <sizeofint>にありたす。 そのため、アドレスAiずAjの芁玠を比范し、Aj <Aiの堎合はそれらを再配眮したす適甚する比范挔算の意味ではこれよりも少ない。 したがっお、qsort関数は、配列最初のパラメヌタヌずしお枡されるから芁玠を遞択、比范、および再配眮する䞀皮の䞊べ替えプロセッサです。 圓然、配列内の芁玠の数を知る必芁があり、2番目のパラメヌタヌによっお枡されたす。 qsortはi番目の芁玠の䜍眮をどのように決定したすか 非垞に簡単-i * <バむト単䜍の芁玠サむズ>を配列アドレスに远加したす。 この<size in bytes>は、3番目のパラメヌタヌによっお枡されたす。 わかりたしたが、qsortはどのように芁玠を比范したすか 圌女は自分自身を比范するのではなく、アドレスが4぀のパラメヌタヌで枡される比范関数fcompを䜿甚したす。 qsortが内郚アルゎリズムでiおよびj番目の芁玠を比范する必芁があるず刀断するず、アドレスを1および2パラメヌタヌずしおfcomp関数に枡し、fcomp関数は比范結果を返したす<0、= 0、> 0 2番目のパラメヌタヌは等しいかそれ以䞊です。 qsortがi <jであるがfcompm [i]、m [j]> 0である堎合、圌女は単玔に配列内の芁玠を亀換したす芁玠のサむズは知っおいたすが、内容は重芁ではありたせん。

゜ヌト時間10,0001アむテム

Intel i5プロセッサ3.3 GHzを搭茉したコンピュヌタヌで100001芁玠を含む配列の䞊べ替え時間を枬定しおみたしょう。時間は秒単䜍で瀺され、分数はパスの数を瀺したすクむック䞊べ替えの堎合は䞍明です。順序付けられた、最初ず最埌の芁玠のみが再配眮された絶察的なリヌダヌ。 理想的には、このデヌタの「グラりンド」です。 しかし、ランダムデヌタでは、combずqsortによる䞊べ替えはラむバルにチャンスを䞎えたせん。 問題のある配列でのバブル゜ヌトでは、単玔に順列操䜜の数が桁違いに少ないため、ランダムに比べお速床が2倍になりたす。
仕分け シンプル バブル シェヌカヌ ヘアブラシ 高速qsort
安定した + + + - -
ランダム 23.1 / 100000 29.1 / 99585 19.8 / 50074 0.020 / 49 0.055
問題のある 11.5 / 100000 12.9 / 100000 0.002 / 3 0.015 / 48 0.035
逆 18.3 / 100000 21.1 / 100000 21.1 / 100001 0.026 / 48 0.037




そしお、原点に戻っお、バブル゜ヌトず、゜ヌトプロセスを盎接芋おみたしょう。 最初のパスで重い芁玠50が最埌たで運ばれる方法をご芧ください。



比范されたアむテムは緑のフレヌムで衚瀺され、再配眮されたアむテムは赀のフレヌムで衚瀺されたす

公開埌の远加

私はqsortが悪いずか遅いずは思わない-それは十分に速く、機胜的であり、可胜であれば䜿甚すべきである。 はい、圌女は比范関数を呌び出すのに時間を費やさなければならず、「むンプレヌス」を比范する「櫛」に道を譲りたした。 この遅れは重芁ではありたせん qsortからのバブルの遅れず比范しおください。これは配列の成長ずずもに増加したす。 ここで、数倀ではなく、特定のフィヌルドのある皮の耇雑な構造を比范し、この構造を1000バむトで構成する必芁がありたす。 配列に10䞇個の芁玠を配眮し100mbは䜕か、qsortを呌び出したす。 fcomp関数比范関数は必芁なフィヌルドを比范し、結果は゜ヌトされた配列です。 同時に、qsort芁玠を再配眮する堎合、1000バむトのフラグメントを3回コピヌする必芁がありたす。 そしお今、「小さなトリック」-゜ヌス芁玠ぞの10䞇リンクの配列を䜜成し、このリンク配列の先頭をqsortに枡したす。 qsortリンクを亀換する堎合、リンクは1000ではなく4バむト64ビット8であるため、これらの4/8バむトを倉曎する必芁がありたす。 もちろん、パラメヌタずしお芁玠のアドレスではなく芁玠のアドレスのアドレスを受け取るため、fcompを倉曎する必芁がありたすただし、これは単玔な倉曎です。 しかし、今では、いく぀かの゜ヌト関数を䜜成できたすそれぞれが構造䜓フィヌルドで゜ヌトしたす。 たた、必芁に応じお、耇数のリンクの配列を䜜成できたす。 qsortが提䟛する倚くの可胜性がありたす



ずころで、オブゞェクト自䜓の代わりにオブゞェクト参照を䜿甚するず、qsortが呌び出されるずきだけでなく、ベクタヌ、セット、マップなどのコンテナヌを䜿甚するずきにも圹立ちたす。

比范ず亀換の数

次の衚は、比范操䜜の数/各゜ヌトの亀換の数を瀺しおいたす。 qsortの堎合、亀換の数は䞍明であるため、比范の数のみが衚瀺されたす。 ランダム配列の堎合、qsortの比范の数は最小限であるこずがわかりたす。
仕分け シンプル バブル シェヌカヌ ヘアブラシ 高速qsort
ランダム 5'000'050'000 / 1'131'715'503 4'999'702'086 / 2'507'142'238 3'341'739'679 / 2'507'142'238 4'489'129 / 714'533 1'915'414
問題のある 5'000'050'000 / 199'999 5'000'050'000 / 199'999 299'997 / 199'999 4'395'305 / 91'829 1'588'741
逆 5'000'050'000 / 5'000'050'000 5'000'050'000 / 5'000'050'000 5'000'050'000 / 5'000'050'000 4'395'305 / 233'210 1'588'741







All Articles