私はpythonにまったく新しいので、クイックソートを実装しようとしています。誰かが私のコードを完成させるのを手伝ってもらえますか?
3つの配列を連結して印刷する方法がわかりません。
def sort(array=[12,4,5,6,7,3,1,15]):
less = []
equal = []
greater = []
if len(array) > 1:
pivot = array[0]
for x in array:
if x < pivot:
less.append(x)
if x == pivot:
equal.append(x)
if x > pivot:
greater.append(x)
sort(less)
sort(pivot)
sort(greater)
def sort(array=[12,4,5,6,7,3,1,15]):
"""Sort the array by using quicksort."""
less = []
equal = []
greater = []
if len(array) > 1:
pivot = array[0]
for x in array:
if x < pivot:
less.append(x)
Elif x == pivot:
equal.append(x)
Elif x > pivot:
greater.append(x)
# Don't forget to return something!
return sort(less)+equal+sort(greater) # Just use the + operator to join lists
# Note that you want equal ^^^^^ not pivot
else: # You need to handle the part at the end of the recursion - when you only have one element in your array, just return the array.
return array
追加メモリなしのクイックソート(インプレース)
使用法:
array = [97, 200, 100, 101, 211, 107]
quicksort(array)
# array -> [97, 100, 101, 107, 200, 211]
def partition(array, begin, end):
pivot = begin
for i in xrange(begin+1, end+1):
if array[i] <= array[begin]:
pivot += 1
array[i], array[pivot] = array[pivot], array[i]
array[pivot], array[begin] = array[begin], array[pivot]
return pivot
def quicksort(array, begin=0, end=None):
if end is None:
end = len(array) - 1
def _quicksort(array, begin, end):
if begin >= end:
return
pivot = partition(array, begin, end)
_quicksort(array, begin, pivot-1)
_quicksort(array, pivot+1, end)
return _quicksort(array, begin, end)
別の簡潔で美しいバージョンがあります
def qsort(arr):
if len(arr) <= 1:
return arr
else:
return qsort([x for x in arr[1:] if x < arr[0]]) + \
[arr[0]] + \
qsort([x for x in arr[1:] if x >= arr[0]])
# this comment is just to improve readability due to horizontal scroll!!!
上記のコードの詳細を説明しましょう
配列arr[0]
の最初の要素をピボットとして選択します
[arr[0]]
qsort
List Comprehension
でピボットより小さい配列の要素
qsort([x for x in arr[1:] if x < arr[0]])
qsort
List Comprehension
を使用したピボットより大きい配列の要素
qsort([x for x in arr[1:] if x >= arr[0]])
Googleで「python quicksort implementation」を検索すると、この質問が最初に表示されます。最初の質問は「コードの修正を支援する」ことでしたが、そのリクエストを無視する多くの答えが既にあることを理解しています:現在 2番目に投票されたもの 、恐ろしい one-liner =陽気な「あなたは解雇された」というコメントと、一般に、インプレースではない多くの実装(つまり、入力リストのサイズに比例して追加のメモリを使用します)。 この回答 はインプレースソリューションを提供しますが、python 2.x
用です。したがって、以下は Rosetta Code からのインプレースソリューションの私の解釈に従います。これはpython 3
でもうまく機能します:
import random
def qsort(l, fst, lst):
if fst >= lst: return
i, j = fst, lst
pivot = l[random.randint(fst, lst)]
while i <= j:
while l[i] < pivot: i += 1
while l[j] > pivot: j -= 1
if i <= j:
l[i], l[j] = l[j], l[i]
i, j = i + 1, j - 1
qsort(l, fst, j)
qsort(l, i, lst)
また、インプレースプロパティを無視する場合は、クイックソートの背後にある基本的なアイデアをよりよく説明する別のバージョンを以下に示します。読みやすさは別として、そのもう1つの利点は、stable(同じ要素がソートされていないリストで使用されていたのと同じ順序でソートされたリストに表示されることです。リスト)。この安定性の特性は、上記のメモリをあまり必要としないインプレース実装では保持されません。
def qsort(l):
if not l: return l # empty sequence case
pivot = l[random.choice(range(0, len(l)))]
head = qsort([elem for elem in l if elem < pivot])
tail = qsort([elem for elem in l if elem > pivot])
return head + [elem for elem in l if elem == pivot] + tail
これにはすでに多くの答えがありますが、このアプローチは最もクリーンな実装だと思います。
def quicksort(arr):
""" Quicksort a list
:type arr: list
:param arr: List to sort
:returns: list -- Sorted list
"""
if not arr:
return []
pivots = [x for x in arr if x == arr[0]]
lesser = quicksort([x for x in arr if x < arr[0]])
greater = quicksort([x for x in arr if x > arr[0]])
return lesser + pivots + greater
もちろん、変数にすべてを保存することをスキップして、次のようにすぐに返すことができます:
def quicksort(arr):
""" Quicksort a list
:type arr: list
:param arr: List to sort
:returns: list -- Sorted list
"""
if not arr:
return []
return quicksort([x for x in arr if x < arr[0]]) \
+ [x for x in arr if x == arr[0]] \
+ quicksort([x for x in arr if x > arr[0]])
Pythonでのクイックソート
実際には、常にPythonが提供する組み込みソートを使用する必要があります。ただし、 quicksort アルゴリズムを理解することは有益です。
ここでの私の目標は、参照資料に戻ることなく、読者が簡単に理解して複製できるように主題を分類することです。
クイックソートアルゴリズムは、基本的に次のとおりです。
データがランダムに分散している場合、ピボットとして最初のデータポイントを選択することは、ランダム選択と同等です。
最初に、コメントと変数名を使用して中間値を指す読みやすい例を見てみましょう。
def quicksort(xs):
"""Given indexable and slicable iterable, return a sorted list"""
if xs: # if given list (or Tuple) with one ordered item or more:
pivot = xs[0]
# below will be less than:
below = [i for i in xs[1:] if i < pivot]
# above will be greater than or equal to:
above = [i for i in xs[1:] if i >= pivot]
return quicksort(below) + [pivot] + quicksort(above)
else:
return xs # empty list
ここで示したアルゴリズムとコードを再度説明するために、ピボットの値を右に、ピボットの値を左に移動し、それらのパーティションを同じ関数に渡してさらにソートします。
これは88文字までゴルフできます。
q=lambda x:x and q([i for i in x[1:]if i<=x[0]])+[x[0]]+q([i for i in x[1:]if i>x[0]])
そこに到達する方法を確認するには、まず読み取り可能な例を使用して、コメントとドキュメント文字列を削除し、インプレースでピボットを見つけます。
def quicksort(xs):
if xs:
below = [i for i in xs[1:] if i < xs[0]]
above = [i for i in xs[1:] if i >= xs[0]]
return quicksort(below) + [xs[0]] + quicksort(above)
else:
return xs
次に、インプレースで以下を見つけます:
def quicksort(xs):
if xs:
return (quicksort([i for i in xs[1:] if i < xs[0]] )
+ [xs[0]]
+ quicksort([i for i in xs[1:] if i >= xs[0]]))
else:
return xs
これで、and
がfalseの場合は前の要素を返し、それ以外の場合はtrueの場合、次の要素を評価して返します。
def quicksort(xs):
return xs and (quicksort([i for i in xs[1:] if i < xs[0]] )
+ [xs[0]]
+ quicksort([i for i in xs[1:] if i >= xs[0]]))
ラムダは1つの式を返すため、1つの式に簡略化したため(読みにくくなったとしても)、ラムダを使用できるようになりました。
quicksort = lambda xs: (quicksort([i for i in xs[1:] if i < xs[0]] )
+ [xs[0]]
+ quicksort([i for i in xs[1:] if i >= xs[0]]))
また、この例に戻すには、関数名と変数名を1文字に短縮し、不要な空白を削除します。
q=lambda x:x and q([i for i in x[1:]if i<=x[0]])+[x[0]]+q([i for i in x[1:]if i>x[0]])
このラムダは、ほとんどのコードゴルフのように、かなり悪いスタイルです。
以前の実装では、不要な余分なリストが大量に作成されていました。これをインプレースで行うことができれば、スペースを無駄にすることはありません。
以下の実装では、Hoareパーティショニングスキームを使用しています。これは ウィキペディアで詳細を読む (ただし、do-whileの代わりにwhile-loopセマンティクスを使用して、partition()
呼び出しごとに最大4つの冗長な計算を削除したようです)狭いステップを外側のwhileループの最後に移動します。).
def quicksort(a_list):
"""Hoare partition scheme, see https://en.wikipedia.org/wiki/Quicksort"""
def _quicksort(a_list, low, high):
# must run partition on sections with 2 elements or more
if low < high:
p = partition(a_list, low, high)
_quicksort(a_list, low, p)
_quicksort(a_list, p+1, high)
def partition(a_list, low, high):
pivot = a_list[low]
while True:
while a_list[low] < pivot:
low += 1
while a_list[high] > pivot:
high -= 1
if low >= high:
return high
a_list[low], a_list[high] = a_list[high], a_list[low]
low += 1
high -= 1
_quicksort(a_list, 0, len(a_list)-1)
return a_list
私はそれを十分にテストしたかどうかわかりません:
def main():
assert quicksort([1]) == [1]
assert quicksort([1,2]) == [1,2]
assert quicksort([1,2,3]) == [1,2,3]
assert quicksort([1,2,3,4]) == [1,2,3,4]
assert quicksort([2,1,3,4]) == [1,2,3,4]
assert quicksort([1,3,2,4]) == [1,2,3,4]
assert quicksort([1,2,4,3]) == [1,2,3,4]
assert quicksort([2,1,1,1]) == [1,1,1,2]
assert quicksort([1,2,1,1]) == [1,1,1,2]
assert quicksort([1,1,2,1]) == [1,1,1,2]
assert quicksort([1,1,1,2]) == [1,1,1,2]
このアルゴリズムは、コンピューターサイエンスコースで頻繁に教えられ、就職の面接で求められます。再帰や分割統治について考えるのに役立ちます。
組み込みの timsort アルゴリズムは非常に効率的であり、再帰の制限があるため、PythonではQuicksortはあまり実用的ではありません。 list.sort
でリストをインプレースでソートするか、 sorted
で新しいソート済みリストを作成します。両方ともkey
およびreverse
引数を取ります。
機能的アプローチ:
def qsort(list):
if len(list) < 2:
return list
pivot = list.pop()
left = filter(lambda x: x <= pivot, list)
right = filter(lambda x: x > pivot, list)
return qsort(left) + [pivot] + qsort(right)
関数型プログラミングのアプローチ
smaller = lambda xs, y: filter(lambda x: x <= y, xs)
larger = lambda xs, y: filter(lambda x: x > y, xs)
qsort = lambda xs: qsort(smaller(xs[1:],xs[0])) + [xs[0]] + qsort(larger(xs[1:],xs[0])) if xs != [] else []
print qsort([3,1,4,2,5]) == [1,2,3,4,5]
ここでの両方の答えは、提供されたリスト(元の質問に答えます)では問題なく機能すると思いますが、一意でない値を含む配列が渡されると壊れます。したがって、完全を期すために、それぞれの小さなエラーを指摘し、それらを修正する方法を説明します。
たとえば、次の配列[12,4,5,6,7,3,1,15,1](1が2回現れることに注意してください)を Brionius アルゴリズム..でソートしようとすると、ある時点で最終的にless配列が空になり、equal配列がペアになります次の反復で分離できない値(1,1)およびlen()> 1...したがって、最終的には無限ループ
lessが空の場合は配列を返すか、notでsortを呼び出すことで修正できます zangw answerのような等しい配列
def sort(array=[12,4,5,6,7,3,1,15]):
less = []
equal = []
greater = []
if len(array) > 1:
pivot = array[0]
for x in array:
if x < pivot:
less.append(x)
if x == pivot:
equal.append(x)
if x > pivot:
greater.append(x)
# Don't forget to return something!
return sort(less)+ equal +sort(greater) # Just use the + operator to join lists
# Note that you want equal ^^^^^ not pivot
else: # You need to hande the part at the end of the recursion - when you only have one element in your array, just return the array.
return array
より洗練されたソリューションも壊れますが、別の原因のために、再帰行にreturn句がありません。これにより、ある時点でNoneが返されます。それをリストに追加してみてください....
修正するには、その行にリターンを追加するだけです
def qsort(arr):
if len(arr) <= 1:
return arr
else:
return qsort([x for x in arr[1:] if x<arr[0]]) + [arr[0]] + qsort([x for x in arr[1:] if x>=arr[0]])
パーティション -より小さな要素が左に移動し、より大きな要素が右に移動する、またはその逆のピボットによって配列を分割します。ピボットは、配列のランダムな要素にすることができます。このアルゴリズムを作成するには、配列の開始インデックスと終了インデックス、およびピボットがどこであるかを知る必要があります。次に、2つの補助ポインターL、Rを設定します。
配列user [...、begin、...、end、...]があります
LおよびRポインターの開始位置
[...、begin、next、...、end、...]
R L
一方、L <終了
1.ユーザー[ピボット]>ユーザー[L]の場合、Rを1つ移動し、ユーザー[R]をユーザー[L]と交換します
2. Lを1つ移動
ユーザー[R]をユーザー[pivot]と交換している間
クイックソート -ピボットによる分割の次の部分ごとに、開始インデックスが終了インデックス以上になるまでパーティションアルゴリズムを使用します。
def qsort(user, begin, end):
if begin >= end:
return
# partition
# pivot = begin
L = begin+1
R = begin
while L < end:
if user[begin] > user[L]:
R+=1
user[R], user[L] = user[L], user[R]
L+= 1
user[R], user[begin] = user[begin], user[R]
qsort(user, 0, R)
qsort(user, R+1, end)
tests = [
{'sample':[1],'answer':[1]},
{'sample':[3,9],'answer':[3,9]},
{'sample':[1,8,1],'answer':[1,1,8]},
{'sample':[7,5,5,1],'answer':[1,5,5,7]},
{'sample':[4,10,5,9,3],'answer':[3,4,5,9,10]},
{'sample':[6,6,3,8,7,7],'answer':[3,6,6,7,7,8]},
{'sample':[3,6,7,2,4,5,4],'answer':[2,3,4,4,5,6,7]},
{'sample':[1,5,6,1,9,0,7,4],'answer':[0,1,1,4,5,6,7,9]},
{'sample':[0,9,5,2,2,5,8,3,8],'answer':[0,2,2,3,5,5,8,8,9]},
{'sample':[2,5,3,3,2,0,9,0,0,7],'answer':[0,0,0,2,2,3,3,5,7,9]}
]
for test in tests:
sample = test['sample'][:]
answer = test['answer']
qsort(sample,0,len(sample))
print(sample == answer)
def Partition(A,p,q):
i=p
x=A[i]
for j in range(p+1,q+1):
if A[j]<=x:
i=i+1
tmp=A[j]
A[j]=A[i]
A[i]=tmp
l=A[p]
A[p]=A[i]
A[i]=l
return i
def quickSort(A,p,q):
if p<q:
r=Partition(A,p,q)
quickSort(A,p,r-1)
quickSort(A,r+1,q)
return A
アルゴリズムには2つの境界が含まれます。1つはピボットより小さい要素(インデックス「j」で追跡)、もう1つはピボットより大きい要素(インデックス「i」で追跡)を持ちます。
各反復で、jをインクリメントすることで新しい要素が処理されます。
不変式:-
不変条件に違反すると、i番目とj番目の要素が入れ替わり、iが増分されます。
すべての要素が処理され、ピボットが分割された後はすべて、ピボット要素が最後の要素よりも小さい要素と交換されます。
これで、ピボット要素はシーケンス内の正しい場所に配置されます。それより前の要素はそれより小さくなり、その後の要素はそれより大きくなり、ソートされません。
def quicksort(sequence, low, high):
if low < high:
pivot = partition(sequence, low, high)
quicksort(sequence, low, pivot - 1)
quicksort(sequence, pivot + 1, high)
def partition(sequence, low, high):
pivot = sequence[low]
i = low + 1
for j in range(low + 1, high + 1):
if sequence[j] < pivot:
sequence[j], sequence[i] = sequence[i], sequence[j]
i += 1
sequence[i-1], sequence[low] = sequence[low], sequence[i-1]
return i - 1
def main(sequence):
quicksort(sequence, 0, len(sequence) - 1)
return sequence
if __== '__main__':
sequence = [-2, 0, 32, 1, 56, 99, -4]
print(main(sequence))
「良い」ピボットは、ほぼ同じサイズの2つのサブシーケンスをもたらします。決定論的に、ピボット要素は、単純な方法で選択するか、シーケンスの中央値を計算することで選択できます。
ピボットを選択する単純な実装は、最初または最後の要素になります。この場合の最悪の実行時間は、サブシーケンスの1つが空になり、再帰呼び出しごとに1つの要素のみが削除されるため、入力シーケンスが既にソートまたは逆ソートされている場合です。
ピボットがシーケンスの中央要素である場合、完全にバランスの取れた分割が達成されます。それよりも多く、それよりも少ない要素が同数存在します。このアプローチにより、全体的な実行時間が改善されますが、はるかに時間がかかります。
ピボットを選択する非決定的/ランダムな方法は、要素をランダムに均一に選択することです。これは単純で軽量なアプローチであり、最悪のシナリオを最小限に抑え、おおよそバランスの取れた分割を実現します。これにより、ピボットを選択する単純なアプローチと中央値アプローチのバランスも確保されます。
アルゴリズムには4つの簡単なステップがあります。
Pythonのアルゴリズムのコード:
def my_sort(A):
p=A[0] #determine pivot element.
left=[] #create left array
right=[] #create right array
for i in range(1,len(A)):
#if cur elem is less than pivot, add elem in left array
if A[i]< p:
left.append(A[i])
#the recurssion will occur only if the left array is atleast half the size of original array
if len(left)>1 and len(left)>=len(A)//2:
left=my_sort(left) #recursive call
Elif A[i]>p:
right.append(A[i]) #if elem is greater than pivot, append it to right array
if len(right)>1 and len(right)>=len(A)//2: # recurssion will occur only if length of right array is atleast the size of original array
right=my_sort(right)
A=left+[p]+right #append all three part of the array into one and return it
return A
my_sort([12,4,5,6,7,3,1,15])
左と右の部分でこのアルゴリズムを再帰的に実行します。
バージョンPython 3.xの場合:読みやすさを向上させるために、operator
モジュールを使用する機能スタイル。
from operator import ge as greater, lt as lesser
def qsort(L):
if len(L) <= 1: return L
pivot = L[0]
sublist = lambda op: [*filter(lambda num: op(num, pivot), L[1:])]
return qsort(sublist(lesser))+ [pivot] + qsort(sublist(greater))
としてテストされています
print (qsort([3,1,4,2,5]) == [1,2,3,4,5])
別のクイックソート実装:
# A = Array
# s = start index
# e = end index
# p = pivot index
# g = greater than pivot boundary index
def swap(A,i1,i2):
A[i1], A[i2] = A[i2], A[i1]
def partition(A,g,p):
# O(n) - just one for loop that visits each element once
for j in range(g,p):
if A[j] <= A[p]:
swap(A,j,g)
g += 1
swap(A,p,g)
return g
def _quicksort(A,s,e):
# Base case - we are sorting an array of size 1
if s >= e:
return
# Partition current array
p = partition(A,s,e)
_quicksort(A,s,p-1) # Left side of pivot
_quicksort(A,p+1,e) # Right side of pivot
# Wrapper function for the recursive one
def quicksort(A):
_quicksort(A,0,len(A)-1)
A = [3,1,4,1,5,9,2,6,5,3,5,8,9,7,9,3,2,3,-1]
print(A)
quicksort(A)
print(A)
または、C/C++変数、ラムダ式、およびif式に相当するPythonを示すワンライナーが必要な場合:
qsort = lambda x=None, *xs: [] if x is None else qsort(*[a for a in xs if a<x]) + [x] + qsort(*[a for a in xs if a>=x])
多くの人がこの質問に正しく答えていることを知っており、それらを読んで楽しんでいます。私の答えはzangwとほぼ同じですが、以前の貢献者は物事が実際にどのように機能するかを視覚的に説明するのに良い仕事をしていなかったと思うので...クイックソート実装のためのシンプルなソリューション。
どのように機能しますか?
ここに、ビジュアルと一緒に行く例があります...(ピボット)9,11,2,0
平均:n対n
最悪の場合:n ^ 2
コード:
def quicksort(data):
if (len(data) < 2):
return data
else:
pivot = data[0] # pivot
#starting from element 1 to the end
rest = data[1:]
low = [each for each in rest if each < pivot]
high = [each for each in rest if each >= pivot]
return quicksort(low) + [pivot] + quicksort(high)
items = [9,11,2,0] print(quicksort(items))
これは、Hoareパーティションスキームを使用し、スワップとローカル変数が少ないクイックソートのバージョンです
def quicksort(array):
qsort(array, 0, len(array)-1)
def qsort(A, lo, hi):
if lo < hi:
p = partition(A, lo, hi)
qsort(A, lo, p)
qsort(A, p + 1, hi)
def partition(A, lo, hi):
pivot = A[lo]
i, j = lo-1, hi+1
while True:
i += 1
j -= 1
while(A[i] < pivot): i+= 1
while(A[j] > pivot ): j-= 1
if i >= j:
return j
A[i], A[j] = A[j], A[i]
test = [21, 4, 1, 3, 9, 20, 25, 6, 21, 14]
print quicksort(test)
def quick_sort(array):
return quick_sort([x for x in array[1:] if x < array[0]]) + [array[0]] \
+ quick_sort([x for x in array[1:] if x >= array[0]]) if array else []
def quick_sort(self, nums):
def helper(arr):
if len(arr) <= 1: return arr
#lwall is the index of the first element euqal to pivot
#rwall is the index of the first element greater than pivot
#so arr[lwall:rwall] is exactly the middle part equal to pivot after one round
lwall, rwall, pivot = 0, 0, 0
#choose rightmost as pivot
pivot = arr[-1]
for i, e in enumerate(arr):
if e < pivot:
#when element is less than pivot, shift the whole middle part to the right by 1
arr[i], arr[lwall] = arr[lwall], arr[i]
lwall += 1
arr[i], arr[rwall] = arr[rwall], arr[i]
rwall += 1
Elif e == pivot:
#when element equals to pivot, middle part should increase by 1
arr[i], arr[rwall] = arr[rwall], arr[i]
rwall += 1
Elif e > pivot: continue
return helper(arr[:lwall]) + arr[lwall:rwall] + helper(arr[rwall:])
return helper(nums)
「真の」インプレース実装[アルゴリズム8.9、8.11、Michael T. GoodrichおよびRoberto TamassiaによるAlgorithm Design and Applications Book]:
from random import randint
def partition (A, a, b):
p = randint(a,b)
# or mid point
# p = (a + b) / 2
piv = A[p]
# swap the pivot with the end of the array
A[p] = A[b]
A[b] = piv
i = a # left index (right movement ->)
j = b - 1 # right index (left movement <-)
while i <= j:
# move right if smaller/eq than/to piv
while A[i] <= piv and i <= j:
i += 1
# move left if greater/eq than/to piv
while A[j] >= piv and j >= i:
j -= 1
# indices stopped moving:
if i < j:
# swap
t = A[i]
A[i] = A[j]
A[j] = t
# place pivot back in the right place
# all values < pivot are to its left and
# all values > pivot are to its right
A[b] = A[i]
A[i] = piv
return i
def IpQuickSort (A, a, b):
while a < b:
p = partition(A, a, b) # p is pivot's location
#sort the smaller partition
if p - a < b - p:
IpQuickSort(A,a,p-1)
a = p + 1 # partition less than p is sorted
else:
IpQuickSort(A,p+1,b)
b = p - 1 # partition greater than p is sorted
def main():
A = [12,3,5,4,7,3,1,3]
print A
IpQuickSort(A,0,len(A)-1)
print A
if __== "__main__": main()
簡単な実装を次に示します。
def quicksort(array):
if len(array) < 2:
return array
else:
pivot= array[0]
less = [i for i in array[1:] if i <= pivot]
greater = [i for i in array[1:] if i > pivot]
return quicksort(less) + [pivot] + quicksort(greater)
print(quicksort([10, 5, 2, 3]))
このアルゴリズムは再帰関数を使用しません。
N
を、len(N) > 0
を含む数値のリストにします。 K = [N]
を設定し、次のプログラムを実行します。
注:これは stable ソートアルゴリズムです。
def BinaryRip2Singletons(K, S):
K_L = []
K_P = [ [K[0][0]] ]
K_R = []
for i in range(1, len(K[0])):
if K[0][i] < K[0][0]:
K_L.append(K[0][i])
Elif K[0][i] > K[0][0]:
K_R.append(K[0][i])
else:
K_P.append( [K[0][i]] )
K_new = [K_L]*bool(len(K_L)) + K_P + [K_R]*bool(len(K_R)) + K[1:]
while len(K_new) > 0:
if len(K_new[0]) == 1:
S.append(K_new[0][0])
K_new = K_new[1:]
else:
break
return K_new, S
N = [16, 19, 11, 15, 16, 10, 12, 14, 4, 10, 5, 2, 3, 4, 7, 1]
K = [ N ]
S = []
print('K =', K, 'S =', S)
while len(K) > 0:
K, S = BinaryRip2Singletons(K, S)
print('K =', K, 'S =', S)
プログラム出力:
K = [[16, 19, 11, 15, 16, 10, 12, 14, 4, 10, 5, 2, 3, 4, 7, 1]] S = []
K = [[11, 15, 10, 12, 14, 4, 10, 5, 2, 3, 4, 7, 1], [16], [16], [19]] S = []
K = [[10, 4, 10, 5, 2, 3, 4, 7, 1], [11], [15, 12, 14], [16], [16], [19]] S = []
K = [[4, 5, 2, 3, 4, 7, 1], [10], [10], [11], [15, 12, 14], [16], [16], [19]] S = []
K = [[2, 3, 1], [4], [4], [5, 7], [10], [10], [11], [15, 12, 14], [16], [16], [19]] S = []
K = [[5, 7], [10], [10], [11], [15, 12, 14], [16], [16], [19]] S = [1, 2, 3, 4, 4]
K = [[15, 12, 14], [16], [16], [19]] S = [1, 2, 3, 4, 4, 5, 7, 10, 10, 11]
K = [[12, 14], [15], [16], [16], [19]] S = [1, 2, 3, 4, 4, 5, 7, 10, 10, 11]
K = [] S = [1, 2, 3, 4, 4, 5, 7, 10, 10, 11, 12, 14, 15, 16, 16, 19]
パーティションのステップで変数を印刷した完全な例:
def partition(data, p, right):
print("\n==> Enter partition: p={}, right={}".format(p, right))
pivot = data[right]
print("pivot = data[{}] = {}".format(right, pivot))
i = p - 1 # this is a dangerous line
for j in range(p, right):
print("j: {}".format(j))
if data[j] <= pivot:
i = i + 1
print("new i: {}".format(i))
print("swap: {} <-> {}".format(data[i], data[j]))
data[i], data[j] = data[j], data[i]
print("swap2: {} <-> {}".format(data[i + 1], data[right]))
data[i + 1], data[right] = data[right], data[i + 1]
return i + 1
def quick_sort(data, left, right):
if left < right:
pivot = partition(data, left, right)
quick_sort(data, left, pivot - 1)
quick_sort(data, pivot + 1, right)
data = [2, 8, 7, 1, 3, 5, 6, 4]
print("Input array: {}".format(data))
quick_sort(data, 0, len(data) - 1)
print("Output array: {}".format(data))
def quick_sort(l):
if len(l) == 0:
return l
pivot = l[0]
pivots = [x for x in l if x == pivot]
smaller = quick_sort([x for x in l if x < pivot])
larger = quick_sort([x for x in l if x > pivot])
return smaller + pivots + larger
def is_sorted(arr): #check if array is sorted
for i in range(len(arr) - 2):
if arr[i] > arr[i + 1]:
return False
return True
def qsort_in_place(arr, left, right): #arr - given array, #left - first element index, #right - last element index
if right - left < 1: #if we have empty or one element array - nothing to do
return
else:
left_point = left #set left pointer that points on element that is candidate to swap with element under right pointer or pivot element
right_point = right - 1 #set right pointer that is candidate to swap with element under left pointer
while left_point <= right_point: #while we have not checked all elements in the given array
swap_left = arr[left_point] >= arr[right] #True if we have to move that element after pivot
swap_right = arr[right_point] < arr[right] #True if we have to move that element before pivot
if swap_left and swap_right: #if both True we can swap elements under left and right pointers
arr[right_point], arr[left_point] = arr[left_point], arr[right_point]
left_point += 1
right_point -= 1
else: #if only one True we don`t have place for to swap it
if not swap_left: #if we dont need to swap it we move to next element
left_point += 1
if not swap_right: #if we dont need to swap it we move to prev element
right_point -= 1
arr[left_point], arr[right] = arr[right], arr[left_point] #swap left element with pivot
qsort_in_place(arr, left, left_point - 1) #execute qsort for left part of array (elements less than pivot)
qsort_in_place(arr, left_point + 1, right) #execute qsort for right part of array (elements most than pivot)
def main():
import random
arr = random.sample(range(1, 4000), 10) #generate random array
print(arr)
print(is_sorted(arr))
qsort_in_place(arr, 0, len(arr) - 1)
print(arr)
print(is_sorted(arr))
if __== "__main__":
main()
Grokkingアルゴリズムからの簡単な実装
def quicksort(arr):
if len(arr) < 2:
return arr #base case
else:
pivot = arr[0]
less = [i for i in arr[1:] if i <= pivot]
more = [i for i in arr[1:] if i > pivot]
return quicksort(less) + [pivot] + quicksort(more)
以下のコードを添付します! ピボット値の位置のため、このクイックソートは優れた学習ツールです。一定の場所にあるので、何度もウォークスルーして、すべてがどのように機能するかを実際に把握できます。実際には、ピボットをランダム化してO(N ^ 2)ランタイムを回避するのが最善です。
def quicksort10(alist):
quicksort_helper10(alist, 0, len(alist)-1)
def quicksort_helper10(alist, first, last):
""" """
if first < last:
split_point = partition10(alist, first, last)
quicksort_helper10(alist, first, split_point - 1)
quicksort_helper10(alist, split_point + 1, last)
def partition10(alist, first, last):
done = False
pivot_value = alist[first]
leftmark = first + 1
rightmark = last
while not done:
while leftmark <= rightmark and alist[leftmark] <= pivot_value:
leftmark = leftmark + 1
while leftmark <= rightmark and alist[rightmark] >= pivot_value:
rightmark = rightmark - 1
if leftmark > rightmark:
done = True
else:
temp = alist[leftmark]
alist[leftmark] = alist[rightmark]
alist[rightmark] = temp
temp = alist[first]
alist[first] = alist[rightmark]
alist[rightmark] = temp
return rightmark
# 编程珠玑实现
# 双向排序: 提高非随机输入的性能
# 不需要额外的空间,在待排序数组本身内部进行排序
# 基准值通过random随机选取
# 入参: 待排序数组, 数组开始索引 0, 数组结束索引 len(array)-1
import random
def swap(arr, l, u):
arr[l],arr[u] = arr[u],arr[l]
return arr
def QuickSort_Perl(arr, l, u):
# 小数组排序i可以用插入或选择排序
# if u-l < 50 : return arr
# 基线条件: low index = upper index; 也就是只有一个值的区间
if l >= u:
return arr
# 随机选取基准值, 并将基准值替换到数组第一个元素
swap(arr, l, int(random.uniform(l, u)))
temp = arr[l]
# 缓存边界值, 从上下边界同时排序
i, j = l, u
while True:
# 第一个元素是基准值,所以要跳过
i+=1
# 在小区间中, 进行排序
# 从下边界开始寻找大于基准值的索引
while i <= u and arr[i] <= temp:
i += 1
# 从上边界开始寻找小于基准值的索引
# 因为j肯定大于i, 所以索引值肯定在小区间中
while arr[j] > temp:
j -= 1
# 如果小索引仍小于大索引, 调换二者位置
if i >= j:
break
arr[i], arr[j] = arr[j], arr[i]
# 将基准值的索引从下边界调换到索引分割点
swap(arr, l, j)
QuickSort_Perl(arr, l, j-1)
QuickSort_Perl(arr, j+1, u)
return arr
print('QuickSort_Perl([-22, -21, 0, 1, 2, 22])',
QuickSort_Perl([-22, -21, 0, 1, 2, 22], 0, 5))