深入理解堆(最大堆,最小堆及堆排序)

基本概念:

1、完全二叉樹:若二叉樹的深度爲h,則除第h層外,其他層的結點全部達到最大值,且第h層的所有結點都集中在左子樹。

2、滿二叉樹:滿二叉樹是一種特殊的的完全二叉樹,所有層的結點都是最大值。

定義:

1、堆是一顆完全二叉樹;

2、堆中的某個結點的值總是大於等於(最大堆)或小於等於(最小堆)其孩子結點的值。

3、堆中每個結點的子樹都是堆樹。

 

堆的操作

假設原始數據爲a[]={4,1,3,2,16,9.10.14.8.7},採用順序存儲對應的完全二叉樹爲:

堆的數據結構如下

struct MaxHeap
{
    EType *heap; //存放數據的空間,下標從1開始存儲數據,下標爲0的作爲工作空間,存儲臨時數據。
    int MaxSize; //MaxSize是存放數據元素空間的大小
    int HeapSize; //HeapSize是數據元素的個數
};
MaxHeap H;

1、構造最大堆

基本思想:首先將每個葉子結點視爲一個堆,再將每個葉子結點於其父節點一起構成一個包含更多結點的堆。所以在構造堆的時候,首先需要找到最後一個結點的父節點,從這個節點開始構造最大堆,直到該節點前面的所有分支節點都處理完畢。

注意: 在二叉樹中,若當前節點的下標爲 i, 則其父節點的下標爲 i/2,其左子節點的下標爲 i*2,其右子節點的下標爲i*2+1;

2、初始化堆
 

void MaxHeapInit(MaxHeap &H)
{
    for(int i=H.HeapSize/2;i>=1;i--)
    {
        H.heap[0]=H.heap[i];
        int son=i*2;
        while(son<H.HeapSize)
        {
            if(son<H.HeapSize&&H.heap[son]<H.heap[son+1])
                son++;
            if(H.heap[i]>H.heap[son])
                break;
            else if(son<H.heapSize&&H.heap[son]>H.heap[son+1]
                {
                    H.heap[son/2]=H.heap[son];
                    son*=2;
                }
        }
        H.heap[son/2]=H.heap[0];
    }
}

下圖是原始數據堆初始化的過程

3、最大堆中插入節點

最大堆中插入節點,先在堆末尾插入該節點,然後按照堆的初始化過程將該節點放入到合適的位置。

void MaxHeapInsert(MaxHeap &H, EType &x)
{
    if(H.HeapSize==H.MaxSize) return false;
    
    int i=++H.HeapSize;
    while(i!=1&&x>H.heap[i/2])
    {
        H.heap[i]=H.heap[i/2];
        i/=2;
    }
    H.heap[i]=x;
    return true;

}

4\最大堆中刪除節點

將最大堆的最後一個節點放到根節點,然後刪除最大值,然後再把新的根節點放到合適的位置

void MaxHeapDelete(MaxHeap &H, EType &x)
{
    if(H.HeapSize==0) return false;
    x=H.heap[1];
    H.heap[0]=H.heap[H.HeapSize--];
    int i=1, son=i*2;
     while(son<H.HeapSize)
        {
            if(son<H.HeapSize&&H.heap[son]<H.heap[son+1])
                son++;
            if(H.heap[i]>H.heap[son])
                break;
             H.heao[i]=H.heap[son];
            i=son;
            son*=2;
        }
        H.heap[i]=H.heap[0];
    return true;
    
}

5、堆排序

#include<iostream>
using namespace std;
 
void swap(int &a, int &b)
{
    int temp=a;
    a=b;
    b=temp;
}
 
void quick_build(int a[], int len, int root)
{
    int left=root*2+1;
    int flag=left;
    while(left<len)
    {
        int right=left+1;
        while(right<len&&a[right]>a[left])
            flag=right;
        
    }
    if(a[root]<a[flag])
    {
        swap(a[root],a[flag]);
        heap_build(a,len,flag);
}
 
void quick_sort(int a[], int len)
{
    for(int i=len/2;i>0;i--)
        heap_build(a,len, i);
    for(int j=len-1;j>0;j--)
    {
        swap(a[0],a[j]);
        heap_build(a,0,j);
    }  
        
}