アルゴリズムのクイックソート(ランダム最適化)

アルゴリズムのクイックソート

@author:Jingdai
@date:2020.10.28

今日LeetCodeをスワイプしたところ、以前に学んだクイックソートを忘れていたことがわかりました。今すぐ記録してください。今後も忘れないようにしたいと思います。

前書き

クイックソート、つまりクイックソート。まあ、言うまでもなく、思考の流れを見てください。

アイデア

1つの文のアイデアは、配列内の数値を決定し、pivotそれよりも小さいすべての数値をその左側に配置し、それよりも大きいすべての数値を右側に配置することです。次に、左側のサブ配列と右側のサブ配列で同じアルゴリズムを再帰的に呼び出して、並べ替えを完了します。次のコードスニペットを参照してください。

public static void quickSort(int[] array, int left, int right) {
     
     
    
    if (left >= right) {
     
     
        return;
    }

    int pivot = positionAndGetPivot(array, left, right);
    quickSort(array, left, pivot - 1);
    quickSort(array, pivot + 1, right);
}

上記のコードを見ると、実際のところ、主な問題は1つを選択pivotし、左側にそれよりも小さい数を、右側にそれよりも大きい数を配置することであることがわかりますそれの番号pivotについてのその選択簡単にするために、最初に左端の配列として選択しpivot、次に2つのポインター変数leftright配列の左端の添え字を選択し、右端のインデックスを記録します。示されているように、pivot数字小さい数字よりも小さい数字を見つけて左に移動し、次に左からpivot数字の大きい数字を見つけるよりも右から始めて、サイクルがleft等しくなるまで右に移動しますright次に、pivot値を置くleftことができる(この時点で位置leftright同じです)。実際、プロセス全体は、アルゴリズムが2つの変数値を交換するのと少し似ています。中間変数を使用する必要がありますが、ここではレコード変数pivot値を使用し、その右側にあるその位置の番号を見つけるための適切な場所を使用します。位置と、他の番号を入れて、左から右に番号PUTを探すことができるまでleftright等しい、その後に記録されている元の中間変数pivotこの位置に配置された値。

ここに画像の説明を挿入します

以下のコードスニペットを見てください。

public static int positionAndGetPivot(int[] array, int left, int right) {
     
     
    int pivotValue = array[left];
    while (left < right) {
     
     
        while (left < right && array[right] >= pivotValue) {
     
     
            right --;
        }
        array[left] = array[right];
        while (left < right && array[left] <= pivotValue) {
     
     
            left ++;
        }
        array[right] = array[left];
    }
    array[left] = pivotValue;
    return left;
}

ただし、上記のコードには少し問題があります。配列内の数値のランダム性が良くない場合、高速ソートの効率はあまり理想的ではありません。ここでは、手動でランダム性を導入できます。上記のようpivot配列の左端の数値を選択するたびに、配列のpivotランダム性が不十分なために発生する効率の問題を防ぐために、ランダム選択できますそれは非常に単純だ、leftrightランダムインデックスとして1を選択しpivot、その後の選択数array[left]、参照してください。次のコードスニペットのように交換しました。

public static int positionAndGetPivot(int[] array, int left, int right) {
     
     

    Random r = new Random();
    int pivotIndex = r.nextInt(right - left + 1) + left;
    int pivotValue = array[pivotIndex];
    array[pivotIndex] = array[left];

    while (left < right) {
     
     
        while (left < right && array[right] >= pivotValue) {
     
     
            right --;
        }
        array[left] = array[right];
        while (left < right && array[left] <= pivotValue) {
     
     
            left ++;
        }
        array[right] = array[left];
    }
    array[left] = pivotValue;
    return left;
}

pivot選択した位置の機能の完了後、このアルゴリズムを再帰的に呼び出すことで、すばやく並べて完了することができます。完全なコードは次のとおりです。

コード

public static void main(String[] args){
     
     

    int[] array = {
     
     4, 5, 9, 2, 1, 4, 1, 3, 5, 6, 7};
    quickSort(array);
    System.out.println(Arrays.toString(array));

}

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

public static void quickSort(int[] array, int left, int right) {
     
     

    if (left >= right) {
     
     
        return;
    }

    int pivot = positionAndGetPivot(array, left, right);
    quickSort(array, left, pivot - 1);
    quickSort(array, pivot + 1, right);
}

public static int positionAndGetPivot(int[] array, int left, int right) {
     
     

    Random r = new Random();
    int pivotIndex = r.nextInt(right - left + 1) + left;
    int pivotValue = array[pivotIndex];
    array[pivotIndex] = array[left];

    while (left < right) {
     
     
        while (left < right && array[right] >= pivotValue) {
     
     
            right --;
        }
        array[left] = array[right];
        while (left < right && array[left] <= pivotValue) {
     
     
            left ++;
        }
        array[right] = array[left];
    }
    array[left] = pivotValue;
    return left;
}

おすすめ

転載: blog.csdn.net/qq_41512783/article/details/109326468