web-dev-qa-db-ja.com

ヒープソート:ソート方法は?

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]
13
I159

私はそれを見つけて、それがどのように機能するかをほぼ理解しました:

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)                                 
1
I159

最大値を取得するにはどうすればよいですか?「取得」する必要はありません。ルートは正確に最大であり、それはヒープの定義されたプロパティです。

ヒープソートを理解するのが難しいと感じる場合は、 この章 が非常に役立ちます。


私はあなたのコードを書き直しました:

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]  
17
Skyler

プッシュアンドポップを使用している場合、または組み込みの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]
3
Jason

ヒープソートの「心臓部」である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
1
BeMeCollective

選択ソートは比較的単純なソートアルゴリズムです。配列を走査し、最初の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() 
0
locojay

最初にヒープを構築する方法の例を含むヒープソートの例

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
0
user2490585