Pythonでヒープソートを実装しようとしていますが、正しく実装できないようです。私はこれを実装しようとしました 擬似コード 、しかし私のコードはソートされません!それはばかげた効果にふるいにかけるだけです。私は問題がこの行にあると思う傾向があります:
ヒープのルート(最大値)をヒープの最後の要素と交換します
最大値を取得するにはどうすればよいですか?
それは私が持っているものです:
def my_heap_sort(sqc):
def heapify(count):
start = (count-2)/2
while start >= 0:
sift_down(start, count-1)
start -= 1
def swap(i, j):
sqc[i], sqc[j] = sqc[j], sqc[i]
def sift_down(start, end):
root = start
while (root * 2 + 1) <= end:
child = root * 2 + 1
temp = root
if sqc[temp] < sqc[child]:
temp = child+1
if temp != root:
swap(root, temp)
root = temp
else:
return
count = len(sqc)
heapify(count)
end = count-1
while end > 0:
swap(end, 0)
end -= 1
sift_down(0, end)
そして、私はほぼ同じ問題の例を見つけました:
def heap_sort_example(a):
def heapify(a):
start = (len(a) - 2) / 2
start -= 1
def sift_down(a, start, end):
root = start
while root * 2 + 1 <= end:
child = root * 2 + 1
if child + 1 <= end and a[child] < a[child+1]:
child += 1
if child <= end and a[root] < a[child]:
a[root], a[child] = a[child], a[root]
root = child
else:
return
heapify(a)
end = len(a) - 1
while end > 0:
a[end], a[0] = a[0], a[end]
sift_down(a, 0, end-1)
end -= 1
結果は異なりますが、どちらもばかげています。
>>> my_heap_sort(sqc)
[2, 7, 1, -2, 56, 5, 3]
>>> heap_sort_example(sqc)
[-2, 1, 7, 2, 56, 5, 3]
私はそれを見つけて、それがどのように機能するかをほぼ理解しました:
def heapsort(sqc):
def down_heap(sqc, k, n):
parent = sqc[k]
while 2*k+1 < n:
child = 2*k+1
if child+1 < n and sqc[child] < sqc[child+1]:
child += 1
if parent >= sqc[child]:
break
sqc[k] = sqc[child]
k = child
sqc[k] = parent
size = len(sqc)
for i in range(size/2-1, -1, -1):
down_heap(sqc, i, size)
for i in range(size-1, 0, -1):
sqc[0], sqc[i] = sqc[i], sqc[0]
down_heap(sqc, 0, i)
この実装は、私自身のアルゴリズムの理解に基づいて書かれています。それはより長いですが、私にとって、このアルゴリズムはこの実装ではるかに明確です。アルゴリズムを理解する必要がある場合は、長い名前を付けると役立つので、長い名前はすべてそのままにしておきました。
def heapsort(sequence):
sequence_length = len(sequence)
def swap_if_greater(parent_index, child_index):
if sequence[parent_index] < sequence[child_index]:
sequence[parent_index], sequence[child_index] =\
sequence[child_index], sequence[parent_index]
def sift(parent_index, unsorted_length):
index_of_greater = lambda a, b: a if sequence[a] > sequence[b] else b
while parent_index*2+2 < unsorted_length:
left_child_index = parent_index*2+1
right_child_index = parent_index*2+2
greater_child_index = index_of_greater(left_child_index,
right_child_index)
swap_if_greater(parent_index, greater_child_index)
parent_index = greater_child_index
def heapify():
for i in range((sequence_length/2)-1, -1, -1):
sift(i, sequence_length)
def sort():
count = sequence_length
while count > 0:
count -= 1
swap_if_greater(count, 0)
sift(0, count)
heapify()
sort()
そして最適化されたバージョン:
def opt_heapsort(s):
sl = len(s)
def swap(pi, ci):
if s[pi] < s[ci]:
s[pi], s[ci] = s[ci], s[pi]
def sift(pi, unsorted):
i_gt = lambda a, b: a if s[a] > s[b] else b
while pi*2+2 < unsorted:
gtci = i_gt(pi*2+1, pi*2+2)
swap(pi, gtci)
pi = gtci
# heapify
for i in range((sl/2)-1, -1, -1):
sift(i, sl)
# sort
for i in range(sl-1, 0, -1):
swap(i, 0)
sift(0, i)
最大値を取得するにはどうすればよいですか?「取得」する必要はありません。ルートは正確に最大であり、それはヒープの定義されたプロパティです。
ヒープソートを理解するのが難しいと感じる場合は、 この章 が非常に役立ちます。
私はあなたのコードを書き直しました:
def swap(i, j):
sqc[i], sqc[j] = sqc[j], sqc[i]
def heapify(end,i):
l=2 * i + 1
r=2 * (i + 1)
max=i
if l < end and sqc[i] < sqc[l]:
max = l
if r < end and sqc[max] < sqc[r]:
max = r
if max != i:
swap(i, max)
heapify(end, max)
def heap_sort():
end = len(sqc)
start = end // 2 - 1 # use // instead of /
for i in range(start, -1, -1):
heapify(end, i)
for i in range(end-1, 0, -1):
swap(i, 0)
heapify(i, 0)
sqc = [2, 7, 1, -2, 56, 5, 3]
heap_sort()
print(sqc)
それは与えます:
[-2, 1, 2, 3, 5, 7, 56]
プッシュアンドポップを使用している場合、または組み込みのheapq libを使用している場合は、文書化されたソリューションを試してください。
from heapq import heappush, heappop
def heapsort(iterable):
h = []
for value in iterable:
heappush(h, value)
return [heappop(h) for i in range(len(h))]
heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ヒープソートの「心臓部」であるheapifyのさまざまな実装は、internetzでは明確ではないことがわかりました。これは、「ヒープ化」の単純だが明確な例を追加することによって、コミュニティを支援するための私の謙虚な試みです。配列操作の余分な混乱を避けるために、ベクトルを使用します。
このメソッドは、配列の1つのセルをヒープ化します。配列全体をヒープ化するには、ループが必要です。配列の中央から実行し、最初に移動します。返されるベクトルは、次の反復で送信するものと同じである必要があります。そうでない場合は、混乱します。例えば:
for (int i = myvector.size()/2; i >= 0; i--) { in = Heapify(in, i);}
vector_of_int Sort::Heapify(vector_of_int in_vector, int in_index)
{
int min_index = in_index; // Track index of smallest out of parent and two children.
int left_child_index = 0;
int right_child_index = 0;
int vector_size = in_vector.size();
left_child_index = LeftChildIndex(in_index);// index of left child, at position 2*in_index
right_child_index = left_child_index + 1;// index of right child, at position 2*in_index + 1
// If left_child_index is not overflowing, suggest swap...
if ((left_child_index) < vector_size)
{
// If parent larger than left child, min_index remembers left child position
if (in_vector[min_index] > in_vector[left_child_index])
{ min_index = left_child_index; }
}
// If right_child_index is is not overflowing, suggest swap...
if (right_child_index < vector_size)
{
// If parent larger than right child, min_index remembers right child position
if (in_vector[min_index] > in_vector[right_child_index])
{ min_index = right_child_index; }
}
// Now min_index has the index of the smallest out of parent and it's two children.
// If the smallest is not the parent, swap parent and smallest.
if (min_index != in_index)
{
in_vector = swap(in_vector, in_index ,min_index);
in_vector = Heapify(in_vector, min_index); // RECURSION IS HERE
}
return in_vector;
}
// End heapify
選択ソートは比較的単純なソートアルゴリズムです。配列を走査し、最初のn個の要素の最小値を抽出してから、次のn-1個の要素の最小値を抽出します......これでO(n ^ 2)アルゴリズムになります。 。
常に最小値を抽出しているので、最小ヒープの使用を検討する必要があります。 O(log n)時間で分を抽出します。最小n回抽出すると、O(n * log n)時間になります。
したがって、ヒープソートの場合は、ヒープを構築する必要があります(heapify O(n))そして配列をトラバースし、最小値をn回抽出します。
python heap を使用して、ヒープを構築するか、独自のヒープを構築できます。
def heapsort(l):
hp = make_heap(l)
for i in range(len(l)):
yield hp.extract_min()
最初にヒープを構築する方法の例を含むヒープソートの例
def findMin(heapArr,i,firstChildLoc,secondChildLoc):
a = heapArr[i]
b = heapArr[firstChildLoc]
c = heapArr[secondChildLoc]
return i if ((a < b) and (a < c)) else firstChildLoc if (b < c) else secondChildLoc
def prelocateUp(heapArr):
l = len(heapArr)
i = l-1
while True:
parentLoc = (i+1)/2 - 1
if parentLoc >= 0:
if heapArr[parentLoc] > heapArr[i]:
temp = heapArr[parentLoc]
heapArr[parentLoc] = heapArr[i]
heapArr[i] = temp
else :
break
i = parentLoc
return heapArr
def prelocateDown(heapArr):
l = len(heapArr)
i = 0
while True:
firstChildLoc = 2*(i+1) - 1
secondChildLoc = 2*(i+1)
if (firstChildLoc > l-1):
break
Elif (secondChildLoc > l-1):
if heapArr[i] > heapArr[firstChildLoc]:
temp = heapArr[i]
heapArr[i] = heapArr[firstChildLoc]
heapArr[firstChildLoc] = temp
break
else :
minLoc = findMin(heapArr,i,firstChildLoc,secondChildLoc)
if minLoc !=i:
temp = heapArr[i]
heapArr[i] = heapArr[minLoc]
heapArr[minLoc] = temp
i = minLoc
else :
break
return heapArr
def heapify(heapArr,op):
if op==1:
heapArr = prelocateUp(heapArr)
else :
heapArr = prelocateDown(heapArr)
return heapArr
def insertHeap(heapArr,num):
heapArr.append(num)
heapArr = heapify(heapArr,1)
return heapArr
def getMin(heapArr):
ele = heapArr[0]
heapArr[0] = heapArr[-1]
heapArr.pop(-1)
heapArr = heapify(heapArr,2)
return ele,heapArr
a=[5,4,8,2,6]
heapArr = []
for i in xrange(0,len(a)):
heapArr = insertHeap(heapArr,a[i])
#No
sortedArr = []
for i in xrange(0,len(a)):
[ele,heapArr] = getMin(heapArr)
sortedArr.append(ele)
print sortedArr