堆排序

1、堆排序算法的基本特性
時間複雜度:O(nlgn)...
//等同於歸併排序
最壞:O(nlgn)
空間複雜度:O(1).
不穩定。算法

 

2、堆與最大堆的創建
要介紹堆排序算法,我們得先從介紹堆開始,而後到創建最大堆,最後纔講到堆排序算法。數組

2.一、堆的介紹
    以下圖,函數

a),就是一個堆,它能夠被視爲一棵徹底二叉樹。
每一個堆對應於一個數組b),假設一個堆的數組A,
咱們用length[A]表述數組中的元素個數,heap-size[A]表示自己存放在A中的堆的元素個數。
固然,就有,heap-size[A]<=length[A]。spa

    樹的根爲A[1],i表示某一結點的下標,
則父結點爲PARENT(i),左兒子LEFT[i],右兒子RIGHT[i]的關係以下:code

PARENT(i)
   return |_i/2_|blog

LEFT(i)
   return 2i排序

RIGHT(i)
   return 2i + 1隊列

    二叉堆根據根結點與其子結點的大小比較關係,分爲最大堆和最小堆。
最大堆:
根之外的每一個結點i都不大於其根結點,即根爲最大元素,在頂端,有
     A[PARENT(i)] (根)≥ A[i] ,ci

最小堆:
根之外的每一個結點i都不小於其根結點,即根爲最小元素,在頂端,有
     A[PARENT(i)] (根)≤ A[i] .element

在本節的堆排序算法中,咱們採用的是最大堆;最小堆,一般在構造最小優先隊列時使用。

    由前面,可知,堆能夠當作一棵樹,因此,堆的高度,即爲樹的高度,O(lgn)。
因此,通常的操做,運行時間都是爲O(lgn)。

具體,以下:
The MAX-HEAPIFY:O(lgn)  這是保持最大堆的關鍵.
The BUILD-MAX-HEAP:線性時間。在無序輸入數組基礎上構造最大堆。
The HEAPSORT:O(nlgn) time, 堆排序算法是對一個數組原地進行排序.
The MAX-HEAP-INSERT, HEAP-EXTRACT-MAX, HEAP-INCREASE-KEY, HEAP-MAXIMUM:O(lgn)。
可讓堆做爲最小優先隊列使用。 

算法實現:

堆的存儲結構:

typedef struct HeapStruct
{
    int *elements;//存儲堆元素的數組 
    int size; //當前堆中元素的個數 
    int capacity;//堆的最大容量 
}MaxHeap;

插入:將新插入的元素放在最後位置,與其父節點比較,若是大於父節點則交換;

刪除:取最大結點(根節點,下標爲一),而後將最後的葉結點放置在根節點,與左右孩子比較,若是小於較大的孩子結點則交換。

創建堆:1.依次調用插入函數,效率不高。

    2.先順序存放元素,而後將整個堆分爲各各小堆,從最後的小堆開始調整,直至整個堆調整完畢,調整方法與刪除方法相同。

總體代碼實現:

#include<stdio.h>
#include<stdlib.h>
#define MaxData 10000
typedef struct HeapStruct
{
    int *elements;//存儲堆元素的數組 
    int size; //當前堆中元素的個數 
    int capacity;//堆的最大容量 
}MaxHeap;
MaxHeap *creat(int MaxSize)//常見最大容量爲MaxSize的空的最大堆 
{
    MaxHeap * H=(MaxHeap *)malloc(sizeof(struct HeapStruct));
    H->elements=(int *)malloc(sizeof(int)*MaxSize+1);// 從下標1開始存放 
    H->size=0;
    H->capacity=MaxSize;
    H->elements[0]=MaxData;
    return H;//定義哨兵爲大於堆中全部可能的元素,便於之後更快操做 
}
void Insert(MaxHeap *H,int item)
{
    int i;
    if(H->size==H->capacity)
    {
        printf("最大堆已滿\n");
        return ;
    }
    i=++H->size;//i指向堆中最後一個元素的位置 
    for( ;item>H->elements[i/2];i=i/2)//與父親結點比較,向下過濾 ,其中element[0]爲哨兵,不小於最大元素,防止越界 
        H->elements[i]=H->elements[i/2];
    H->elements[i]=item;//將item插入 
}
int DeleteMax(MaxHeap *H)
{
    int parent,child;
    int max,temp;
    if(H->size==0 )
    {
        printf("堆爲空");
        return ;
    }
    max=H->elements[1];
    temp=H->elements[(H->size)--];
    for(parent=1;parent*2<=H->size;parent=child)//parent<=H->size判斷有沒有左兒子,若是左兒子都沒有,右兒子不可能有 
    {
        child=parent*2;//child指向左兒子 
        if(child!=H->size&&H->elements[child]<H->elements[child+1])//child!=H->size若是不是最後一個,說明存在右兒子 
            child++; //child指向左右孩子中較大的
        if(temp>=H->elements[child])
            break;
        else
            H->elements[parent]=H->elements[child]; 
    }
    H->elements[parent]=temp;
    return max; 
}
MaxHeap* CreatHeap(void)//分割成許多小堆,從最後一個小堆,依次向前調整 
{
    MaxHeap *H=creat(500);
    while(1)
    {
        int temp;
        printf("請輸入數據(-1結束);\n");
        scanf("%d",&temp);
        if(temp==-1)
            break;
        else
            H->elements[++H->size]=temp;
    }
    int parent,child,temp,n;
    n=H->size/2;//指向最後一個有孩子的父結點 
    while(n>0)
    {
        parent=n; 
        temp=H->elements[parent];
        for( ;parent*2<=H->size;parent=child)
        {
            child=parent*2;//child指向左兒子 
            if(child!=H->size&&H->elements[child]<H->elements[child+1])
                child++; 
            if(temp>=H->elements[child])
                break;
            else
                H->elements[parent]=H->elements[child]; 
        }
        H->elements[parent]=temp;
        n--;
    }
    return H;
 } 
int main()
{
    MaxHeap *H=CreatHeap();
    int i; 
  scanf("%d",&i); Insert(H,i
); while(H->size!=0) { int i=DeleteMax(H); printf("%4d",i); } return 0; }

常見應用:優先隊列

相關文章
相關標籤/搜索