Wenxin Yiyan VS Xunfei Xinghuo VS chatgpt (73) -- アルゴリズム入門 7.1 4 つの質問

4. 非昇順でソートできるように QUICKSORT を変更するにはどうすればよいですか?

一言で言えば:

クイックソート (クイックソート) は、分割統治戦略に基づいて設計された、一般的に使用される並べ替えアルゴリズムです。デフォルトでは、クイックソートは昇順で並べ替えます。クイックソートを変更して非増分ソートを実装するには、比較と交換のロジックを調整する必要があります。

以下は、非増分クイックソート用に変更された Python コードです。

def quicksort(arr):  
    if len(arr) <= 1:  
        return arr  
    else:  
        pivot = arr[len(arr)//2]  
        left = [x for x in arr if x > pivot]  
        middle = [x for x in arr if x == pivot]  
        right = [x for x in arr if x < pivot]  
        return quicksort(left) + middle + quicksort(right)  
  
print(quicksort([3,6,8,10,1,2,1]))

上記のコードでは、最初に中間値 (ピボット) を選択し、配列を 3 つの部分 (ピボットより大きい、ピボットに等しい、ピボット未満) に分割します。次に、ピボットより小さい部分と大きい部分に対してクイックソートを再帰的に実行します。最後に、3 つの部分を結合して戻ります。このようにして、非増加的にソートされた配列を取得できます。

上記のコードでは、不必要なリストの作成とマージ操作が多数含まれるため、パフォーマンスの問題が発生する可能性があることに注意してください。運用環境では、この問題を回避するために、クイックソートのインプレース バージョンを使用することをお勧めします。ただし、ここではわかりやすくするためにこのように使用しています。

ここに画像の説明を挿入

シュンフェイ・スパーク:

PARTITION 関数を変更することで、クイックソートの非増分ソートを実装できます。PARTITION 関数では、x を A[r] に設定し、次のコードを使用して配列を非昇順に並べ替えます。

for j in range(p, r):
    if A[j] <= x:
        i = i + 1
        A[i], A[j] = A[j], A[i]
A[i + 1], A[r] = A[r], A[i + 1]
return i + 1

これにより、クイックソートで配列が非昇順に並べ替えられます。

ここに画像の説明を挿入

360 スマートブレイン:

QUICKSORT は比較に基づくソート アルゴリズムであり、分割統治の考え方によってソート対象の配列をいくつかの部分列に分割し、各部分列を再帰的にソートし、最後にそれらをマージして順序付けされた配列を取得します。

非昇順でソートするように QUICKSORT を変更する場合は、次の方法を検討できます。

1. カスタム比較機能

QUICKSORT で使用される比較関数は、配列内の 2 つの要素の値を比較し、その値に応じてそれらがどのサブシーケンスのセットに含まれるかを決定します。非昇順で並べ替えたい場合は、小さい要素が最初に来て、大きい要素が後に来るように比較関数をカスタマイズできます。

具体的な実装方法は次のコードを参照できます。


def custom_sort(arr): 

    for i in range(len(arr)): 

        min_index = i 

        for j in range(i+1, len(arr)): 

            if arr[j] < arr[min_index]: 

                min_index = j 

        arr[i], arr[min_index] = arr[min_index], arr[i] 

    return arr 

 

def quick_sort(arr, left, right): 

    if left >= right: 

        return 

 

    pivot_index = partition(arr, left, right) 

    quick_sort(arr, left, pivot_index-1) 

    quick_sort(arr, pivot_index+1, right) 

 

def partition(arr, left, right): 

    pivot = arr[right] 

    i = left - 1 

    for j in range(left, right): 

        if arr[j] <= pivot: 

            i += 1 

            arr[i], arr[j] = arr[j], arr[i] 

    arr[i+1], arr[right] = arr[right], arr[i+1] 

    return i+1 

 

カスタム _sort 関数では、2 つのネストされたループを使用して配列全体を走査し、現在の部分配列内の最小の要素を見つけて、それを現在の部分配列の最後の要素と交換し、最後に Quick_sort 関数を再帰的に呼び出します。左と右を並べ替えます。サブアレイ。カスタム _sort 関数の戻り値は、ソートされた配列です。

2. 比較順序を変更する

カスタム比較関数に加えて、比較順序を変更することで非昇順で並べ替えるという目的も達成できます。具体的には、まず配列の最初の要素と 2 番目の要素を比較し、最初の要素が 2 番目の要素より大きい場合は、それらの位置を交換し、次に 2 番目の要素と 3 番目の要素を比較し、最後の要素まで比較します。要素。これにより、配列の要素が昇順ではなく降順になることが保証されます。

具体的な実装方法は次のコードを参照できます。


def quick_sort(arr, left, right): 

    if left >= right: 

        return 

 

    pivot_index = partition(arr, left, right) 

    quick_sort(arr, left, pivot_index-1) 

    quick_sort(arr, pivot_index+1, right) 

 

def partition(arr, left, right): 

    pivot = arr[right] 

    i = left - 1 

    for j in range(left, right): 

        if arr[j] <= pivot: 

            i += 1 

            arr[i], arr[j] = arr[j], arr[i] 

    arr[i+1], arr[right] = arr[right], arr[i+1] 

    return i+1 

 

パーティション関数では、まず配列の最後の要素をピボット (ピボット) として選択し、次に配列全体を走査し、ピボット以下の要素をその左側に配置し、ピボットより大きい要素をその左側に配置します。右に移動し、最後にピボットの位置を返します。

チャットグラム:

クイックソートは比較に基づく並べ替えアルゴリズムであり、その基本的な考え方は、分割統治によってシーケンスを 2 つの部分シーケンスに分割し、その後 2 つの部分シーケンスを再帰的に並べ替えることです。デフォルトでは、クイックソートは昇順で並べ替えます。つまり、小さい要素が最初に配置されます。

クイックソートで非昇順に並べ替えられるようにするには、アルゴリズムの基本ロジックを少し変更します。具体的には、並べ替え順序を降順に変更できます。つまり、大きい要素が前の位置に配置されます。

以下は、単純な非インクリメントのクイックソートの実装です。

def quicksort_nondecreasing(arr):  
   if len(arr) <= 1:  
       return arr  
   pivot = arr[-1]  
   left = []  
   right = []  
   for i in range(len(arr) - 1):  
       if arr[i] < pivot:  
           left.append(arr[i])  
       else:  
           right.append(arr[i])  
   return quicksort_nondecreasing(left) + [pivot] + quicksort_nondecreasing(right)  

この実装では、最後の要素をピボットとして選択し、シーケンス全体を反転して、大きい要素が左側に、小さい要素が右側になるようにします。次に、左と右のサブシーケンスを再帰的に並べ替えて、ピボットと結合します。

標準のクイックソートの時間計算量が O(nlogn) であるのに対し、この増加しないクイックソートは時間計算量が O(n^2) であるため、最適ではないことに注意してください。したがって、非昇順でソートする必要がある場合は、マージ ソートやヒープ ソートなど、他のより適切なアルゴリズムを使用することをお勧めします。

ここに画像の説明を挿入

トンイ・チェンチアン:

非昇順でソートできるように QUICKSORT を変更できます。これは、ピボット値を選択するときに、固定の最小値または最大値の代わりに乱数を使用することで実現できます。具体的には、QUICKSORT への各再帰呼び出しの前に、配列要素をピボット値としてランダムに選択できます。このようにして、配列自体が非インクリメントであっても、ランダムで非インクリメントのソート結果が得られます。

変更された QUICKSORT 関数の Python 実装は次のとおりです。

import random

def quicksort(arr, start, end):
    if start < end:
        pivot_index = random.randint(start, end)  # 随机选择枢轴值
        pivot = arr[pivot_index]
        left = [x for x in arr[start:end] if x < pivot]
        middle = [x for x in arr[start:end] if x == pivot]
        right = [x for x in arr[start:end] if x > pivot]
        quicksort(left, 0, len(left) - 1)
        quicksort(right, 0, len(right) - 1)
        return middle + left + right

# 测试
arr = [3, 6, 2, 8, 1, 9, 5, 4]
quicksort(arr, 0, len(arr) - 1)
print(arr)

この実装では、Python の組み込みランダム モジュールを使用して乱数を生成します。QUICKSORT への各再帰呼び出しの前に、ピボット値として配列要素をランダムに選択します。次に、配列を 3 つの部分、つまりピボット値より小さい要素、ピボット値に等しい要素、ピボット値より大きい要素に分割します。左部分と右部分を再帰的に並べ替えてから、それらを中央の部分とマージして、最終的な並べ替え結果を形成します。

オリジナルの QUICKSORT とこの修正されたバージョンを比較することで、その動作を検証できます。増加しない配列の場合、元の QUICKSORT は増加するソート結果を返します (ピボット値として常に最小値または最大値を選択するため)。改良された QUICKSORT はピボット値をランダムに選択できるため、増加しないソート結果を取得できます。以下は、非インクリメント配列に対するこれら 2 つの関数の動作を比較する例です。

import random

arr = [3, 6, 2, 8, 1, 9, 5, 4]
arr = sorted(arr)  # 先将数组排序为递增序
print("原始的QUICKSORT")
quicksort(arr, 0, len(arr) - 1)
print("修改后的QUICKSORT")
quicksort(arr, 0, len(arr) - 1)

出力は次のとおりです。

原始的QUICKSORT
[1, 2, 3, 4, 5, 6, 8, 9]
修改后的QUICKSORT
[1, 2, 3, 4, 5, 6, 8, 9]

元の QUICKSORT は増分ソート結果を返すのに対し、変更された QUICKSORT はランダムな非増分ソート結果を返すことがわかります。

ここに画像の説明を挿入

ここに画像の説明を挿入

ここに画像の説明を挿入

天宮:

QuickSort アルゴリズムを変更して非増分並べ替えを実装するには、次の手順に従います。

1. 比較関数を変更します。元の比較関数を変更して、非増分順序で比較します。たとえば、降順で並べ替える場合は、比較関数を のif (a > b)代わりに に変更できますif (a < b)

2. Exchange 要素のコードを変更します。Exchange 要素のコードをtemp = a[i]; a[i] = a[j]; a[j] = tempに変更しますtemp = a[i]; a[i] = a[j]; a[j] = temp; if (i != j) { temp = a[i]; a[i] = a[j]; a[j] = temp; }これにより、要素が交換されるときに、並べ替えられた要素の相対位置が変更されなくなります。

3. 挿入した要素のコードを変更します。挿入した要素のコードをfor (int k = i; k >= 1; k--)に変更しますfor (int k = i + 1; k <= n; k++)これにより、要素を挿入するときに、すでに並べ替えられている要素の相対位置が変更されなくなります。

4. 結果を返すコードを変更します。結果を返すコードをreturn i;に変更しますreturn j;これにより、結果が返されるときに、並べ替えられた要素の相対位置が変更されないことが保証されます。

非昇順での並べ替えを処理するには追加のコードが必要になるため、変更された QuickSort アルゴリズムは元のアルゴリズムよりも遅くなる可能性があることに注意してください。

ここに画像の説明を挿入

チャットポイント:

クイックソート アルゴリズムを変更して非増加ソートを実装するには、元のクイックソート アルゴリズムにいくつかの変更を加えるだけで済みます。以下は、変更されたクイックソート アルゴリズムの擬似コードです。

function quicksort(array, low, high):
    if low < high:
        pivot = partition(array, low, high)
        quicksort(array, low, pivot - 1)
        quicksort(array, pivot + 1, high)

function partition(array, low, high):
    pivot = array[high]
    i = low - 1
    for j = low to high - 1:
        if array[j] >= pivot:
            i = i + 1
            swap array[i] and array[j]
    swap array[i + 1] and array[high]
    return i + 1

次の変更点に注意してください。

1.quicksort関数内で、再帰呼び出しの順序を変更します。最初に左側の部分配列 ( quicksort(array, low, pivot - 1)) をソートし、次に右側の部分配列 ( quicksort(array, pivot + 1, high)) をソートします。これにより、要素が処理される順序が変更され、配列が非昇順でソートされるようになります。

2.partition関数内で、ピボット以上の要素を部分配列の左側に移動します。判定条件を変更しarray[j] >= pivot、要素がpivot以上の場合に配列の左側に入れ替えます。

このように、変更されたクイックソート アルゴリズムは昇順ではない順序で並べ替えられます。これは配列要素の順序にのみ影響し、他のデータ構造の処理には影響しないことに注意してください。

ここに画像の説明を挿入

要約する

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/weixin_48502062/article/details/132188217