堆排序


                                                 一 初識堆

數據結構是一種數組,它可以視為一顆完全二叉樹。如下圖:

       

圖中的樹是數組,A={16, 14, 10, 8, 7, 9, 3, 7},圈內表示數值,圈外紅色的數字表示數組的下標。

array_size是數組的大小(此時是8),heap_size是構建堆的元素的多少。滿足heap_size<= array_size

給定某結點的下表i,其父結點下標為PARENT(i), 左兒子下標為LEFT(i), 右兒子下標為RIGHT(i)。滿足

         PARENT(i) = int((i-1)/2) ;   LEFT(i) = 2*i+1;   RIGHT(i)=2*i+2

最大堆滿足:對於任何結點(除根節點)PARENT(i) > i

最小堆滿足:對於任何結點(除根節點)PARENT(i) <i

葉子節點(下標):int(i/2), int(i/2)+1......array_size

下面的介紹以最大堆為例

                                              二 保持堆的性質

       最大堆的性質為 PARENT(i) > i,因此對於特定的結點,應滿足比左右兒子都大

    在上圖中下標為1的結點值為2,左孩子為4,右孩子為1,1結點比左孩子小,就讓1結點和3結點數值換過來。若此時4結點大於4,就把1結點和4結點數值換過來。

參考程序:

void MAX_HEAPIFY(int *A, int heap_size, int i)   //i 為待處理保持性質的結點下標
{
        int l = 2 * i + 1;                       //左孩子 int r = 2 * i + 2;                       //右孩子 int largest = i;
        if(l < heap_size && A[largest] < A[l])   // 左孩子數值大
        {
            largest = l;
        }
     if(r < heap_size && A[largest] < A[r])   //右孩子數值大
{ largest
= r; } if(largest != i) { int tmp = A[i]; A[i] = A[largest]; A[largest] = tmp; MAX_HEAPIFY(A, heap_size, largest); //再從數值大的結點繼續往下遞歸處理 } }

                                              三 構建堆

      從底向上使得每個結點保持堆的性質就可以構建堆,因為葉子節點就自己,無兒女,因此從倒數第一個非葉子節點開始依次往上構建,直到樹根位置,而葉子節點開始的位置是int(i/2),因此第一個令其保持性質的結點下標為int((i-1)/2)。接着是int((i-1)/2-1)一直到0為止。下圖表示了構建堆的詳細過程:

圖中有9個結點,int(9/2)= 4, 從4-1=3開始(依次是4 3 2 1 0)。注意是從后往前,為何不是從前往后,顯然如果是上圖中,從0開始,是6和3交換,我們知道在最大堆中根是最大的,可是從前往后的話,最大值7在無出頭之日。

參考程序:

void BUILD_MAX_HEAP(int *A, int array_size, int heap_size)
{
        int i;
        for (i=array_size/2-1; i>=0; i--)
        {
            MAX_HEAPIFY(A, heap_size, i);
        }
}

                                              四 堆排序

      最大堆把最大值排到了首個位置A[0],這是如果把最大值和最后一個值A[heap_size-1]換過來,再使A[0]保持堆的性質,再使heap_size自建。重復以上過程,就是個非遞減排序。下圖是一個事例過程:

參考程序:

void HEAP_SORT(int *A, int array_size, int heap_size)
{
        int tmp;
        BUILD_MAX_HEAP(A, array_size, heap_size);
        while(heap_size > 1)
        {
            tmp = A[0];
            A[0] = A[heap_size-1];
            A[heap_size] = tmp;
            heap_size--;
            MAX_HEAPIFY(A, heap_size, 0);
        }
}

測試

#include <iostream>
#include <vector>
using namespace std;
void maxHeapify(int A[], int lens, int i)
{
    if (A == NULL || i >= lens)
        return;
    int l = 2 * i + 1;
    int r = 2 * i + 2;
    int largest = i;
    if (l < lens || A[i] > A[largest])
        largest = l;
    if (r < lens && A[r] > A[largest])
        largest = r;
    if (largest != i)
    {
        int tmp = A[largest];
        A[largest] = A[i];
        A[i] = tmp;
        maxHeapify(A, lens, largest);
    }
}
void buildHeap(int A[], int lens)
{
    if (A == NULL || lens <= 0)
        return;
    int mid = (lens-2) / 2;
    for (int i = mid; i >= 0; --i)
        maxHeapify(A, lens, i);
}
void heapSort(int A[], int lens)
{
    buildHeap(A, lens);
    while (lens > 1)
    {
        int tmp = A[lens-1];
        A[lens-1] = A[0];
        A[0] = tmp;
        --lens;
        maxHeapify(A, lens, 0);
    }
}
void tranverse(int A[], int lens)
{
    if (A == NULL || lens <= 0)
        return;
    for (int i = 0; i < lens; ++i)
        cout << A[i] << "  ";
    cout << endl;
}
    
int main()
{
    int A[] = {3, 2, 8, 7, 0, 11};
    int lens = sizeof(A) / sizeof(*A);
    tranverse(A, lens);
//    buildHeap(A, lens);
//    tranverse(A, lens);
    heapSort(A, lens);
    tranverse(A, lens);
}

                                            

五 堆操作

1.HEAP_MAXIMUM(A) 找出最大的元素

int  HEAP_MAXIMUM(int *A)
{
        return A[0];
}

2.int HEAP_EXTRACT_MAX(int *A, int heap_size) 找出堆中最大元素,並刪除,保持堆

int HEAP_EXTRACT_MAX(int *A, int heap_size)
{
        int max;
        max = A[0];
        A[0] = A[heap_size-1];
        heap_size--;
        MAX_HEAPIFY(A, heap_size, 0);
        
        return max;
}

3. void HEAP_INCREASE_KEY(int *A, int heap_size, int i, int key) 第i個位置出若key比原來大,就改成key,保持堆

void HEAP_INCREASE_KEY(int *A, int heap_size, int i, int key)
{
        int tmp;
        if(A[i] > key)
        {
            printf("The key is smaller than A[i]");
        }
        else
        {
            A[i] = key;
            while(i>=1 && A[(i-1)/2] < A[i])
            {
                tmp = A[i];
                A[i] = A[(i-1)/2];
                A[(i-1)/2] = tmp;
                i = (i-1)/2;
                MAX_HEAPIFY(A, heap_size, i);
            }
        }

}

4.void MAX_HEAP_INSERT(int *A, int array_size, int heap_size, int key) 堆中插入元素

void MAX_HEAP_INSERT(int *A, int array_size, int heap_size, int key)
{
        array_size++;
        heap_size++;
        A[heap_size] = -32768;
        HEAP_INCREASE_KEY(A, heap_size, heap_size-1, key);
}

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM