みなさん、ようこそ〜
一緒に学び、一緒に進歩しましょう〜
1. 高速ソートの原則:一般に3つのステップに分けられます:
1。参照値としてソートする間隔から数値を選択します(通常は左端の数値を選択します)
2。パーティション:ソートする範囲全体をトラバースします。参照値よりも小さい(等しいを含めることができる)参照値の左側に配置し、参照値よりも大きい値(等しいを含めることができる)を参照値の右側に配置します。
3.分割統治のアイデアを採用し、セル間の長さが<= 1になるまで、左右のセルを同じように扱い、比較を終了します。
配列[3,5,2,7,9,4,8]を例にとると、高速ソートのプロセスです。
次に、比較のプロセスはパーティションのプロセスです
。Javaがこの部分を実現するには3つの方法があります。速いソート:
1つのホーア方法
方法.Digging 2
3
ホーア方法のアイデアをトラバーサル方法の前と後:
掘削方法のアイデア:基本的なアイデアはホア法と同じですが、交換ではなく、直接割り当て(掘削ピット+充填ピット)
前後のトラバーサルのアイデア:2番目の番号からトラバースし、最初の番号よりも小さい(または大きい)番号を見つけてから、最初の番号と交換します。アイデアは比較的単純で、誰もが見ることで理解できますコードで。
3. パフォーマンス分析:
時間計算量:最高O(n log(n))最悪O(n ^ 2)平均複雑度:O(n log(n))
空間計算量:最高:O(n log(n))最悪: O(n)平均:O(n log(n))
安定性:不安定
第四に、 高速キューの最適化方法について:
一般的なインタビュアーは質問するときにこれらの側面を考慮します。
1. paititionセクションを掘り下げる(細部の最適化)
2。比較の数が比較的少ない場合、クイックソートは最速ではありません;(間隔内の数が特定のしきい値(16)よりも小さい場合は、補間行)
3。特別な数値を選択する方法を最適化します-----比較値として左端の数値を
選択しますa。ランダムに選択しますb。いくつかの数値を選択し、中央のサイズ値を選択します(3番目の数値は選択)
4。等しい値を特に扱います
5つ目は、クイックソートのコード実装部分:( 3つの方法)は、小さいものから大きいものへのソートを実現することです。
public class Hoare {
public static void quickSort(long[] array) {
quickSortInternal(array, 0, array.length - 1);
}
// 区间是 [lowIndex, highIndex]
private static void quickSortInternal(long[] array,int lowIndex,int highIndex) {
// 由于是闭区间,所以,区间内个个数需要加个 1
int size = highIndex - lowIndex + 1;
if (size <= 1) {
return;
}
// 选择其中一个数(选最左边的) —— array[lowIndex]
// 执行 partition,小的放左,大的放右
// keyIndex 是经过 partition 之后,选出来的数最终所在下标
int keyIndex = partition(array, lowIndex, highIndex);
// 分别对左右区间进行相同的处理 —— 递归方法
quickSortInternal(array, lowIndex, keyIndex - 1);
quickSortInternal(array, keyIndex + 1, highIndex);
}
// 区间是 array[lowIndex, highIndex]
// 1. 选择 array[lowIndex] 作为特殊的数
// 2. 需要遍历整个区间(不能遗漏任何的数)和 选出来的数比较
// 3. 保证 小于等于的在左边,大于等于的在右边(但没有顺序要求)
private static int partition(long[] array, int lowIndex, int highIndex) {
// 选择合适的方法
return partitionHover(array, lowIndex, highIndex);
}
private static void swap(long[] array, int index1, int index2) {
long t = array[index1];
array[index1] = array[index2];
array[index2] = t;
}
private static int partitionHover(long[] array, int lowIndex, int highIndex) {
int leftIndex = lowIndex;
int rightIndex = highIndex;
// 选择的数是最左边的一个
long key = array[lowIndex];
// 选择了最左边,从右边先走
// 停止条件 leftIndex == rightIndex
// 循环的继续的条件 leftIndex < rightIndex
while (leftIndex < rightIndex) {
while (leftIndex < rightIndex && array[rightIndex] >= key) {
rightIndex--;
}
// 说明 [rightIndex] 遇到了小的了
while (leftIndex < rightIndex && array[leftIndex] <= key) {
leftIndex++;
}
// 说明 [leftIndex] 遇到了大的了
swap(array, leftIndex, rightIndex);
}
swap(array, lowIndex, leftIndex);
return leftIndex;
}
//挖坑
private static int partitionHoare(long[] array,int lowIndex,int highIndex){
int leftIndex=lowIndex;
int rightIndex=highIndex;
long key=array[lowIndex];
while(leftIndex<rightIndex){
while(leftIndex<rightIndex&&array[highIndex]>=key){
rightIndex--;
}
//右边的值
array[leftIndex]=array[rightIndex];
while(leftIndex<rightIndex&&array[leftIndex]<key){
leftIndex++;
}
array[rightIndex]=array[leftIndex];
}
array[leftIndex]=key;
return leftIndex;
}
//前后遍历的方法
private static int partition前后(long[] array,int lowIndex,int highIndex){
int separateIndex=lowIndex+1;
for(int i=lowIndex+1;i<=highIndex;i++){
if(array[i]<array[lowIndex]){
swap(array,i,separateIndex);
separateIndex++;
}
}
swap(array,lowIndex,separateIndex-1);
return separateIndex-1;
}