logo

QuickSort – データ構造とアルゴリズムのチュートリアル

クイックソート に基づく並べ替えアルゴリズムです。 分割統治アルゴリズム これは、要素をピボットとして選択し、ソートされた配列内の正しい位置にピボットを配置することで、選択したピボットを中心に指定された配列を分割します。

クイックソートはどのように機能しますか?

主要なプロセス クイックソート です パーティション() 。パーティションの目標は、ソートされた配列内の正しい位置にピボット (ピボットとして任意の要素を選択できます) を配置し、すべての小さい要素をピボットの左側に配置し、大きい要素をすべてピボットの右側に配置することです。 。

ピボットが正しい位置に配置された後、分割はピボットの各側で再帰的に実行され、これにより最終的に配列が並べ替えられます。



クイックソートの仕組み

クイックソートの仕組み

if-else Java
推奨練習 クイックソート 試してみましょう!

ピボットの選択:

ピボットの選択にはさまざまな選択肢があります。

  • 常に最初の要素をピボットとして選択します
  • 常に最後の要素をピボットとして選択します (以下で実装)
  • ランダムな要素をピボットとして選択します
  • 中央をピボットとして選択します。

パーティションアルゴリズム:

ロジックは単純で、一番左の要素から開始して、より小さい (または等しい) 要素のインデックスを追跡します。 。トラバース中に、より小さい要素が見つかった場合は、現在の要素を arr[i] と交換します。それ以外の場合、現在の要素は無視されます。

次の例を使用して、パーティションとクイック ソート アルゴリズムの仕組みを理解しましょう。

Linuxでスクリプトを実行する方法

arr[] = {10, 80, 30, 90, 40} を考えてみましょう。

  • 10 をピボットと比較し、ピボットより小さいのでそれに応じて配置します。

QuickSort のパーティション: ピボットを 10 と比較

  • 80をピボットと比較してください。ピボットよりも大きいです。

QuickSort のパーティション: ピボットを 80 と比較

  • 30 をピボットと比較します。 pivotよりも小さいのでそれに合わせて配置します。

QuickSort のパーティション: ピボットを 30 と比較

  • 90 をピボットと比較します。ピボットよりも大きいです。

QuickSort のパーティション: ピボットを 90 と比較

  • ピボットを正しい位置に配置します。

QuickSort のパーティション: ピボットを正しい位置に配置します。

クイックソートの図:

分割プロセスは再帰的に実行されるため、ソートされた配列内の実際の位置にピボットが配置され続けます。ピボットを実際の位置に繰り返し配置すると、配列がソートされます。

以下の図に従って、パーティション アルゴリズムの再帰的実装が配列の並べ替えにどのように役立つかを理解してください。

Javaの継承
  • メインアレイの初期パーティション:

クイックソート: パーティションの実行

  • サブ配列の分割:

クイックソート: パーティションの実行

クイックソートのコード実装:

C++
#include  using namespace std; int partition(int arr[],int low,int high) {  //choose the pivot    int pivot=arr[high];  //Index of smaller element and Indicate  //the right position of pivot found so far  int i=(low-1);    for(int j=low;j<=high-1;j++)  {  //If current element is smaller than the pivot  if(arr[j]
C
// C program for QuickSort #include  // Utility function to swap tp integers void swap(int* p1, int* p2) {  int temp;  temp = *p1;  *p1 = *p2;  *p2 = temp; } int partition(int arr[], int low, int high) {  // choose the pivot  int pivot = arr[high];  // Index of smaller element and Indicate  // the right position of pivot found so far  int i = (low - 1);  for (int j = low; j <= high - 1; j++) {  // If current element is smaller than the pivot  if (arr[j] < pivot) {  // Increment index of smaller element  i++;  swap(&arr[i], &arr[j]);  }  }  swap(&arr[i + 1], &arr[high]);  return (i + 1); } // The Quicksort function Implement void quickSort(int arr[], int low, int high) {  // when low is less than high  if (low < high) {  // pi is the partition return index of pivot  int pi = partition(arr, low, high);  // Recursion Call  // smaller element than pivot goes left and  // higher element goes right  quickSort(arr, low, pi - 1);  quickSort(arr, pi + 1, high);  } } int main() {  int arr[] = { 10, 7, 8, 9, 1, 5 };  int n = sizeof(arr) / sizeof(arr[0]);    // Function call  quickSort(arr, 0, n - 1);    // Print the sorted array  printf('Sorted Array
');  for (int i = 0; i < n; i++) {  printf('%d ', arr[i]);  }  return 0; } // This Code is Contributed By Diwakar Jha>
ジャワ
// Java implementation of QuickSort import java.io.*; class GFG {  // A utility function to swap two elements  static void swap(int[] arr, int i, int j)  {  int temp = arr[i];  arr[i] = arr[j];  arr[j] = temp;  }  // This function takes last element as pivot,  // places the pivot element at its correct position  // in sorted array, and places all smaller to left  // of pivot and all greater elements to right of pivot  static int partition(int[] arr, int low, int high)  {  // Choosing the pivot  int pivot = arr[high];  // Index of smaller element and indicates  // the right position of pivot found so far  int i = (low - 1);  for (int j = low; j <= high - 1; j++) {  // If current element is smaller than the pivot  if (arr[j] < pivot) {  // Increment index of smaller element  i++;  swap(arr, i, j);  }  }  swap(arr, i + 1, high);  return (i + 1);  }  // The main function that implements QuickSort  // arr[] -->ソートされる配列、 // low --> 開始インデックス、 // high --> 終了インデックス static voidquickSort(int[] arr, int low, int high) { if (low< high) {  // pi is partitioning index, arr[p]  // is now at right place  int pi = partition(arr, low, high);  // Separately sort elements before  // partition and after partition  quickSort(arr, low, pi - 1);  quickSort(arr, pi + 1, high);  }  }  // To print sorted array  public static void printArr(int[] arr)  {  for (int i = 0; i < arr.length; i++) {  System.out.print(arr[i] + ' ');  }  }  // Driver Code  public static void main(String[] args)  {  int[] arr = { 10, 7, 8, 9, 1, 5 };  int N = arr.length;  // Function call  quickSort(arr, 0, N - 1);  System.out.println('Sorted array:');  printArr(arr);  } } // This code is contributed by Ayush Choudhary // Improved by Ajay Virmoti>
パイソン
# Python3 implementation of QuickSort # Function to find the partition position def partition(array, low, high): # Choose the rightmost element as pivot pivot = array[high] # Pointer for greater element i = low - 1 # Traverse through all elements # compare each element with pivot for j in range(low, high): if array[j] <= pivot: # If element smaller than pivot is found # swap it with the greater element pointed by i i = i + 1 # Swapping element at i with element at j (array[i], array[j]) = (array[j], array[i]) # Swap the pivot element with # the greater element specified by i (array[i + 1], array[high]) = (array[high], array[i + 1]) # Return the position from where partition is done return i + 1 # Function to perform quicksort def quicksort(array, low, high): if low < high: # Find pivot element such that # element smaller than pivot are on the left # element greater than pivot are on the right pi = partition(array, low, high) # Recursive call on the left of pivot quicksort(array, low, pi - 1) # Recursive call on the right of pivot quicksort(array, pi + 1, high) # Driver code if __name__ == '__main__': array = [10, 7, 8, 9, 1, 5] N = len(array) # Function call quicksort(array, 0, N - 1) print('Sorted array:') for x in array: print(x, end=' ') # This code is contributed by Adnan Aliakbar>
C#
// C# implementation of QuickSort using System; class GFG {  // A utility function to swap two elements  static void swap(int[] arr, int i, int j)  {  int temp = arr[i];  arr[i] = arr[j];  arr[j] = temp;  }  // This function takes last element as pivot,  // places the pivot element at its correct position  // in sorted array, and places all smaller to left  // of pivot and all greater elements to right of pivot  static int partition(int[] arr, int low, int high)  {  // Choosing the pivot  int pivot = arr[high];  // Index of smaller element and indicates  // the right position of pivot found so far  int i = (low - 1);  for (int j = low; j <= high - 1; j++) {  // If current element is smaller than the pivot  if (arr[j] < pivot) {  // Increment index of smaller element  i++;  swap(arr, i, j);  }  }  swap(arr, i + 1, high);  return (i + 1);  }  // The main function that implements QuickSort  // arr[] -->ソートされる配列、 // low --> 開始インデックス、 // high --> 終了インデックス static voidquickSort(int[] arr, int low, int high) { if (low< high) {  // pi is partitioning index, arr[p]  // is now at right place  int pi = partition(arr, low, high);  // Separately sort elements before  // and after partition index  quickSort(arr, low, pi - 1);  quickSort(arr, pi + 1, high);  }  }  // Driver Code  public static void Main()  {  int[] arr = { 10, 7, 8, 9, 1, 5 };  int N = arr.Length;  // Function call  quickSort(arr, 0, N - 1);  Console.WriteLine('Sorted array:');  for (int i = 0; i < N; i++)  Console.Write(arr[i] + ' ');  } } // This code is contributed by gfgking>
JavaScript
// Function to partition the array and return the partition index function partition(arr, low, high) {  // Choosing the pivot  let pivot = arr[high];    // Index of smaller element and indicates the right position of pivot found so far  let i = low - 1;    for (let j = low; j <= high - 1; j++) {  // If current element is smaller than the pivot  if (arr[j] < pivot) {  // Increment index of smaller element  i++;  [arr[i], arr[j]] = [arr[j], arr[i]]; // Swap elements  }  }    [arr[i + 1], arr[high]] = [arr[high], arr[i + 1]]; // Swap pivot to its correct position  return i + 1; // Return the partition index } // The main function that implements QuickSort function quickSort(arr, low, high) {  if (low < high) {  // pi is the partitioning index, arr[pi] is now at the right place  let pi = partition(arr, low, high);    // Separately sort elements before partition and after partition  quickSort(arr, low, pi - 1);  quickSort(arr, pi + 1, high);  } } // Driver code let arr = [10, 7, 8, 9, 1, 5]; let N = arr.length; // Function call quickSort(arr, 0, N - 1); console.log('Sorted array:'); console.log(arr.join(' '));>
PHP
 // code ?>// この関数は最後の要素をピボットとして使用します。 // ピボットを正しい位置として配置します。 // ソートされた配列内で、小さい要素はすべてピボットの左側に配置され、 // 大きい要素はすべてピボットの右側に配置されます。 $low,$high) { // ピボット要素を選択 $pivot= $arr[$high]; // 小さい要素のインデックスであり、 // ピボットの正しい位置を示します $i=($low-1); for($j=$low;$j<=$high-1;$j++) { if($arr[$j]<$pivot) { // Increment index of smaller element $i++; list($arr[$i],$arr[$j])=array($arr[$j],$arr[$i]); } } // Pivot element as correct position list($arr[$i+1],$arr[$high])=array($arr[$high],$arr[$i+1]); return ($i+1); } // The main function that implement as QuickSort // arr[]:- Array to be sorted // low:- Starting Index //high:- Ending Index function quickSort(&$arr,$low,$high) { if($low<$high) { // pi is partition $pi= partition($arr,$low,$high); // Sort the array // Before the partition of Element quickSort($arr,$low,$pi-1); // After the partition Element quickSort($arr,$pi+1,$high); } } // Driver Code $arr= array(10,7,8,9,1,5); $N=count($arr); // Function Call quickSort($arr,0,$N-1); echo 'Sorted Array:
'; for($i=0;$i<$N;$i++) { echo $arr[$i]. ' '; } //This code is contributed by Diwakar Jha>

出力
Sorted Array 1 5 7 8 9 10>

クイックソートの複雑さの分析 :

時間計算量:

  • 最良の場合 : Ω (N log (N))
    クイックソートの最良のシナリオは、各ステップで選択されたピボットが配列をほぼ均等な半分に分割するときに発生します。
    この場合、アルゴリズムはバランスの取れたパーティションを作成し、効率的な並べ替えにつながります。
  • 平均ケース: θ ( N log (N))
    クイックソートの平均的なケースのパフォーマンスは、実際には通常非常に優れており、最速のソート アルゴリズムの 1 つとなっています。
  • 最悪の場合: O(N2)
    クイックソートの最悪のシナリオは、各ステップでのピボットによって一貫して非常に不均衡なパーティションが発生する場合に発生します。配列がすでにソートされており、ピボットが常に最小または最大の要素として選択される場合。最悪のシナリオを緩和するために、適切なピボット (例: 3 の中央値) を選択したり、ランダム化アルゴリズム (Randomized Quicksort ) を使用して並べ替え前に要素をシャッフルしたりするなど、さまざまなテクニックが使用されます。
  • 補助スペース: 再帰的なスタック領域を考慮しない場合は、O(1)。再帰的なスタック領域を考慮すると、最悪の場合、クイックソートは ( N )。

クイックソートの利点:

  • これは、問題の解決を容易にする分割統治アルゴリズムです。
  • 大規模なデータセットでは効率的です。
  • 機能するには少量のメモリしか必要としないため、オーバーヘッドが低くなります。

クイックソートの欠点:

  • 最悪の場合の時間計算量は O(N2)、ピボットの選択が不適切な場合に発生します。
  • これは、小さなデータセットには適した選択ではありません。
  • これは安定した並べ替えではありません。つまり、2 つの要素が同じキーを持つ場合、クイック ソートの場合、それらの相対的な順序は並べ替えられた出力に保持されません。これは、ここでは (元の要素を考慮せずに) ピボットの位置に従って要素を交換しているためです。ポジション)。