通常のクイックソート
ベース値ベースを見つけてから、ベースの左側の数値がベースよりも小さくなり、ベースの右側の数値がベースよりも大きくなるように、1回の旅行で並べ替えます。次に、2つのサブアレイソートに分けます。このような再帰。
public class quicksort {public static <tは比較可能<? super t >> void sort(t [] arr){sort(arr、0、arr.length -1);} public static <tは比較可能<? super t >> void sort(t [] arr、int left、int right){if(left> = right)return; int p = pertition(arr、左、右); sort(arr、左、p -1); sort(arr、p + 1、右);} private static <tは比較可能<? super t >> intパーティション(t [] arr、int left、int右){t base = arr [左]; int j =左; for(int i =左+1; i <=右; i ++){if(base.compareto(arr [i])> 0){j ++; swap(arr、j、i); sorting} public static void swap(object arr、int i、int j){if(i!= j){object temp = arr [i]; arr [j]; arr [j] = temp;}} private static void printarr(object ar){for(object o:arr){for(object o:arr){ {system.out.print(o); System.out.print( "/t");} system.out.println();} public static void main(string args []){integer [] arr = {3、5、1、7、2、9、8、0、4、6}; printarr(arr); 6sort(arr); printarr(arr); // 0 1 2 3 4 5 6 7 8 9}}クイックソート最適化:ベース値ベースをランダムに選択します
アレイがほぼ順序付けられると、高速性のパフォーマンスが低くなります(各順序の後、左と右のサブの再帰サイズが非常に異なり、最終的にはより大きな部分がO(n^2)に達する可能性が高いため)。
解決策:基準値は、毎回最初の番号を取得するのではなく、ランダムに選択されます。これは、「ほぼ順序付けられた配列」によって邪魔されることはありません。しかし、「ほとんど注文不足アレイ」のソートパフォーマンスはわずかに低下する可能性があります。少なくとも、ソート前に交換される部分が多くあります。このスワッピングは、オーダーの外では無意味です...多くの「運」コンポーネントがあります...
public class quicksort {public static <tは比較可能<? super t >> void sort(t [] arr){sort(arr、0、arr.length -1);} public static <tは比較可能<? super t >> void sort(t [] arr、int left、int right){if(left> = right)return; int p = pertition(arr、左、右); sort(arr、左、p -1); sort(arr、p + 1、右);} private static <tは比較可能<? super t >> intパーティション(t [] arr、int左、右){//ソートする前に、参照値を乱数と交換します。このようにして、参照値はランダムです。 //アレイが比較的順序付けられている場合、左と右側の再帰スケールが一貫していないため、最悪の複雑さのスワップ(arr、左、(int)(math.random()*(右 - 左+1)+左); t base = arr [左]; > 0){j ++; swap(arr、j、i);}} swap(arr、left、j); return j; //嘘の並べ替え後に基準値の下コーナーを返します} public static void swap(object [] arr、int i、int j){if(i!= j){object temp = arr [i] = arr [j]; arr [j]; arr [j]; printArr(object [] arr){for(object o:arr){system.out.print(o); system.out.print( "/t");} system.out.println();} public static void main(string args []){integer [] arr = {3、5、5、1、7、9、8、4、4、6、6}; 0 4 6sort(arr); printarr(arr); // 0 1 2 3 4 5 6 7 8 9}}クイックソートは最適化され続けます:挿入並べ替えを組み合わせて使用する
クイックオーダーは、問題の規模を継続的に削減して、サブ問題を解決し、継続的な再帰を必要とすることです。ただし、再帰は十分に小さく、この不安定な +再帰が実行され続けている場合、効率はあまり良くない場合があります。
したがって、問題が小さく、ほぼ整然としている場合、挿入ソートはうまく機能します。多くの場合、そのようなコメントはarrays.sort()にjavaに付属しています:「小さな配列に挿入ソートを使用してください」、「最小の配列に挿入ソート」
public class quicksort {public static <tは比較可能<? Super t >> void sort(t [] arr){sort(arr、0、arr.length -1、16);}/*** @param arrayはソートされる* @param左左*右右* @param k @param k @param kは速いソートがサブプローム<= k、sortipized*/param <t> compparam <同等の<? Super T >> void sort(t [] arr、int left、int右、int k){//スケール時間は挿入によってソートされます(右 - 左<= k){arr、左、右); return;} int p = pertition(arr、左、右);ソート(arr、左、p -1、k); Super T >> void InsertionSort(T [] arr、int l、int r){for(int i = l + 1; i <= r; i ++){t cur = arr [i]; int j = i-1;同等の拡張<? super t >> intパーティション(t [] arr、int左、右){//ソートする前に、参照値を乱数と交換します。このようにして、参照値はランダムです。 //アレイが比較的順序である場合、左側と右側の再帰スケールが一貫していないため、最悪の時間の複雑さのスワップ(arr、左、(int)(math.random() *(右 - 左 + 1) +左); t base = arr [左]; int j =左; 0){j ++; swap(arr、j、i);}} swap(arr、left、j); return j; //嘘をついた後、ベース値の下コーナーを返します} public static void swap(object [] arr、int i、int j){if(i!= j){object temp = arr [i] = arr [j]; arr [j]; arr [j]; arr [j]; printArr(object [] arr){for(object o:arr){system.out.print(o); system.out.print( "/t");} system.out.println();} public static void main(string args []){integer [] arr = {3、5、5、1、7、9、8、4、4、6、6}; 0 4 6sort(arr); printarr(arr); // 0 1 2 3 4 5 6 7 8 9}}クイックソートは最適化され続けます:双方向の高速ソート
最初の通常のクイックソートでは、ベースの左側のベース値はベースよりも小さいと言われていますが、右側のベースはベース以上です。これらのベースに等しいものが右に集まります(または、サイズの関係が左に集まることをわずかに変更します)。とにかく、それは脇に集まります。アレイで多くの数字が繰り返されると、2つの潜水艦のサイズに大きな違いが生じます。この時点で、私はそれらをまとめるのではなく、ベースの両側にベースに等しい数字を割り当てたいと思います。
(注:コードをテストするときは、挿入ソートの一部を見渡して、以下のコードのように見えることをお勧めします...それ以外の場合は、データボリュームがk = 16未満の場合、挿入ソートが実行されます...)
public class quicksort {public static <tは比較可能<? Super t >> void sort(t [] arr){sort(arr、0、arr.length -1、16);}/*** @param arrayはソートされる* @param左左*右右* @param k @param k @param kは速いソートがサブプローム<= k、sortipized*/param <t> compparam <同等の<? Super T >> void sort(t [] arr、int left、int right、int k){// insertionsort(arr、左、右); // return; //} if(左> =右)return(arr、左、右);ソート(arr、左、右);ソート(arr、左、p -1、k) Super T >> void InsertionSort(T [] arr、int l、int r){for(int i = l + 1; i <= r; i ++){t cur = arr [i]; int j = i-1;同等の拡張<? super t >> intパーティション(t [] arr、int左、右){//ソートする前に、参照値を乱数と交換します。このようにして、参照値はランダムです。 //アレイが比較的順序付けられている場合、左側と右側の再帰スケールが一貫していないため、最悪の時間の複雑さのスワップ(arr、左、(int)(math.random() *(右 - 左 + 1) +左); t base = arr [左]; 1; //前の行で言及されている[左+1 .........右]間隔の場合、[左+1 ...... i)閉じた右の開いた間隔はベース以下を左にします。 int j =右;/左、ベースよりも小さい最初の要素をスキャンしてから、j> = left && arr [j] .compareto(base)> 0)j-; sorting} public static void swap(object arr、int i、int j){if(i!= j){object temp = arr [i]; arr [j]; arr [j] = temp;}} private static void printarr(object ar){for(object o:arr){for(object o:arr){ {system.out.print(o); System.out.print( "/t");} system.out.println();} public static void main(string args []){integer [] arr = {3、5、1、7、2、9、8、0、4、6}; printarr(arr); 6sort(arr); printarr(arr); // 0 1 2 3 4 5 6 7 8 9}}高速ソートを最適化し続ける:2つの高速ソートにはスワップを必要としない、Exchangeを使用する
上記の2つのパスがベースよりも大きい値とベースよりも少ない値を見つけると、SWAP()メソッドを使用して交換します。 2桁の交換には、3番目の変数温度の動作が含まれ、より読み取りおよび書き込み操作があります。次に、直接割り当て方法を使用して、右よりも少ないものと左よりも大きいものを配置します。私とjが会うとき、その位置はベースを配置する必要がある場所です。この旅行は完了しました。再走行するだけです。
public class quicksort {public static <tは比較可能<? Super t >> void sort(t [] arr){sort(arr、0、arr.length -1、16);}/*** @param arrayはソートされる* @param左左*右右* @param k @param k @param kは速いソートがサブプローム<= k、sortipized*/param <t> compparam <同等の<? Super T >> void sort(t [] arr、int left、int right、int k){// insertionsort(arr、左、右); // return; //} if(左> =右)return(arr、左、右);ソート(arr、左、右);ソート(arr、左、p -1、k) Super T >> void InsertionSort(T [] arr、int l、int r){for(int i = l + 1; i <= r; i ++){t cur = arr [i]; int j = i-1;同等の拡張<? super t >> intパーティション(t [] arr、int左、右){//ソートする前に、参照値を乱数と交換します。このようにして、参照値はランダムです。 //アレイが比較的順序付けられている場合、左と右側の再帰スケールが一貫していないため、最悪の時間の複雑さのスワップ(arr、左、(int)(math.random() *(右 - 左 + 1) +左); t base = arr [左];左; //前の行で言及されている[左+1 .........右]間隔の場合、[左+1 ...... i)左クリップされた右クリックされた間隔値は、ベース以下です。 int j =右; // [左+1 ......右]の前の2行で言及されている間隔では、jは(j ......右]左オープンおよび右クリックされた間隔の値がベース以下であることを意味します。 j-; arr [i] = arr [j]; //左から右にスキャンし、ベースよりも大きい最初の要素をスキャンしてから、そこで停止します(j && arr [i] .compareto(base)<0)i ++; i、int j){if(i!= j){object temp = arr [i]; arr [i] = arr [j]; arr [j] = temp;}} private static void printarr(object o:arr){for(object o:arr){system.out.print(o); system.out.out( "/t"); out.putip.print() args []){integer [] arr = {3、5、1、7、2、9、8、0、4、6}; printarr(arr); // 3 5 1 7 2 9 8 0 4 6sort(arr); // 0 1 2 3 4 5 6 7 8 9}}}クイックソートは最適化され続けます:大量のデータと多くの繰り返しが使用される場合は、3ウェイの高速ソートを使用します
配列を3つのパスに分けます。最初のパスはベースよりも小さく、2番目のパスはベースに等しく、3番目のパスはベースよりも大きくなります。
ポインターを使用して、次の場合の場合はスキャンします。
1. CURによって指された数はベースよりも少ない、次に:arr [cur]とarr [i]の値を交換し、次にi ++、cur ++を交換します。
2。curによって指された数はベースに等しい、次に:cur ++
3。CURによって指された数はベースよりも大きく、次に:arr [cur]とarr [j]の値を交換し、j--。
cur> jの場合、3つのパスすべてが完了したことを意味します。
public class quicksort {public static <tは比較可能<? Super t >> void sort(t [] arr){sort(arr、0、arr.length -1、16);}/*** @param arrayはソートされる* @param左左*右右* @param k @param k @param kは速いソートがサブプローム<= k、sortipized*/param <t> compparam <同等の<? Super t >> void sort(t [] arr、int left、int right、int k){// insertionsort(arr、左、右); // return; //} if(left> = right)return; int [] ret = partition(arr、左、右);ソート(arr、左、ret [0]、k); super t >> void insertionsort(t [] arr、int l、int r){for(int i = l + 1; i <= r; i ++){t cur = arr [i]; int j = i-1; @param arr arrayソート* @paramは、配列の左の境界を左に並べ替えます* @param右に配列の正しい境界を右に並べ替える* @param <t> generics* @return*/private static <tは同等の<? super t >> int []パーティション(t [] arr、int left、int右){//ソートする前に、参照値を乱数と交換します。このようにして、参照値はランダムです。 //アレイが比較的順序である場合、左側と右側の再帰スケールが一貫していないため、最悪の時間の複雑さのスワップ(arr、左、(int)(math.random() *(右 - 左 + 1) +左); t base = arr [左];次の3つのチャネル(間隔)に分割されていますint i =左; //左は[lleft ...左)左の閉じた右の開いた間隔の数字がベースよりも小さいことを示しますint j =右; //左は(right ...右)左と右の閉じた間隔の数字がベースよりも大きいことを示します。 <= j){if(arr [cur] .compareto(base)== 0){cur ++;} else if(arr [cur] .compareto(base)<0){swap(arr、cur ++、i ++);}サブプロムは、iおよびjの左と右を解く必要があります} public static void swap(object [] arr、int i、int j){if(i!= j){object temp = arr [i] = arr [j]; arr [j] = temp;}} private static void printarr(object] arr [] arr) {system.out.print(o); System.out.print( "/t");} system.out.println();} public static void main(string args []){integer [] arr = {3、5、1、7、2、9、8、0、4、6}; printarr(arr); 6sort(arr); printarr(arr); // 0 1 2 3 4 5 6 7 8 9}}要約します
上記は、Javaプログラミングの実装クイックソートと最適化コードのすべての詳細な説明です。私はそれが誰にでも役立つことを願っています。興味のある友人は、このサイトの他の関連トピックを引き続き参照できます。欠点がある場合は、それを指摘するためにメッセージを残してください。このサイトへのご支援をありがとうございました!