堆排序詳解以及java實現

前言

臨近畢業,開始找工做,近期一直在看算法導論(CLRS)同時各類刷題。但願之後有時間把全部學習心得和刷題心得記錄下來。java

         堆排序和合並排序同樣,是一種時間複雜度爲O(nlgn)的算法,同時和插入排序同樣,是一種就地排序算法(不須要額外的存儲空間)。堆排序須要用到一種被稱爲最大堆的數據結構,與java或者lisp的gc不同,這裏的堆是一種數據結構,他能夠被視爲一種徹底二叉樹,即樹裏面除了最後一層其餘層都是填滿的。也正是由於這樣,樹裏面每一個節點的子女和雙親節點的序號均可以根據當前節點的序號直接求出。算法

  Parent(i)=i/2數組

  Left(i)=2*i數據結構

Right(i)=2*i+1

 

 

如上圖所示,1位置的子女節點分別爲2,3  2節點的子女節點爲4,5 2的雙親節點爲1 考察其餘節點也很容易發現上述關係。最大堆是一種特殊的堆,其特色是每一個雙親節點的值都比子女節點大。他的這一特色使得他能夠實現nlgn的就地排序。如今咱們先來看看怎麼構建和保持一個最大堆。學習

最大堆的構建和保持

         咱們如今有一個數組A,大小是n,假設其中元素按照徹底二叉樹的方式排列。如何將其構形成一個最大堆?首先咱們知道最大堆的每一個子樹都符合最大堆的性質(根節點值大於全部子節點)。同時咱們知道序號爲(n/2+1)~n的元素都是葉子節點(由於其子女節點的序號都大於n,即說明沒有子女節點),所以咱們構建最大堆的操做就在序號爲1~n/2的元素內進行(其餘元素已知足最大堆性質)。咱們定義以下操做maxify(i):將以i位置節點爲根的子樹改形成最大堆。其操做內容以下:對於每一個節點i,咱們考察他與子女節點的大小,若是他比某個子女節點小,則將他與子女節點中最大的那個互換位置,而後在相應的子女節點位置重複操做,直到到達堆的葉子節點或者考察的位置比子女節點的值都要大爲止。由此可知咱們構造最大堆buildmaxheap的過程就是在每一個內部節點上調用maxify過程,依次到樹的根部,此時其左右子樹都是最大堆,如今在根節點調用maxify即完成了最大堆的構造。ui

堆排序的操做

         有了最大堆的基礎結構後,咱們就能夠利用最大堆的性質進行排序HeapSort,咱們從根節點開始操做,由於根節點是這個數組中最大的元素,所以咱們將其於數組中最後一個元素對換(排序後,最大元素應該在最後)將heapsize減1,而後再在根節點出調用maxify過程將新的堆從新最大堆化。依次循環,咱們每次都能將現有堆中最大的元素放到堆末尾。最後就完成了整個排序過程。操做狀況見下圖(只列出了前4步)this

        

 

 代碼及運行結果

public class MaxHeap {
int[] heap;
int heapsize;
public MaxHeap(int[] array)
{
    this.heap=array;    
    this.heapsize=heap.length;
}
public void BuildMaxHeap()
{
    for(int i=heapsize/2-1;i>=0;i--)
    {
        Maxify(i);//依次向上將當前子樹最大堆化
    }
}
public void HeapSort()
{
    for(int i=0;i<heap.length;i++)
    {
        //執行n次,將每一個當前最大的值放到堆末尾
        int tmp=heap[0];
        heap[0]=heap[heapsize-1];
        heap[heapsize-1]=tmp;
        heapsize--;
        Maxify(0);
    }
}
public void Maxify(int i)
{
    int l=Left(i);
    int r=Right(i);
    int largest;
    
    if(l<heapsize&&heap[l]>heap[i])
        largest=l;
    else
        largest=i;
    if(r<heapsize&&heap[r]>heap[largest])
        largest=r;
    if(largest==i||largest>=heapsize)//若是largest等於i說明i是最大元素 largest超出heap範圍說明不存在比i節點大的子女
        return ;
    int tmp=heap[i];//交換i與largest對應的元素位置,在largest位置遞歸調用maxify
    heap[i]=heap[largest];
    heap[largest]=tmp;
    Maxify(largest);
}
public void IncreaseValue(int i,int val)
{
    heap[i]=val;
    if(i>=heapsize||i<=0||heap[i]>=val)
        return;
    int p=Parent(i);
    if(heap[p]>=val)
        return;
    heap[i]=heap[p];
    IncreaseValue(p, val);
}

private int Parent(int i)
{
    return (i-1)/2;
}
private int Left(int i)
{
    return 2*(i+1)-1;
}
private int Right(int i)
{
    return 2*(i+1);
}
}

 

public class Demo {
public static void main(String[] args)
{
    int[] array=new int[]{1,2,3,4,7,8,9,10,14,16};
    MaxHeap heap=new MaxHeap(array);
    System.out.println("執行最大堆化前堆的結構:");
    printHeapTree(heap.heap);
    heap.BuildMaxHeap();
    System.out.println("執行最大堆化後堆的結構:");
    printHeapTree(heap.heap);
    heap.HeapSort();
    System.out.println("執行堆排序後數組的內容");
    printHeap(heap.heap);
    
}
private static void printHeapTree(int[] array)
{
    for(int i=1;i<array.length;i=i*2)
    {
        for(int k=i-1;k<2*(i)-1&&k<array.length;k++)
        {
            System.out.print(array[k]+" ");
        }
        System.out.println();
    }    
}
private static void printHeap(int[] array)
{
    for(int i=0;i<array.length;i++)
    {
        System.out.print(array[i]+" ");
    }
}


}

 

相關文章
相關標籤/搜索