1. 程式人生 > >Java實現堆排序(大根堆)

Java實現堆排序(大根堆)

  堆排序是一種樹形選擇排序方法,它的特點是:在排序的過程中,將array[0,...,n-1]看成是一顆完全二叉樹的順序儲存結構,利用完全二叉樹中雙親節點和孩子結點之間的內在關係,在當前無序區中選擇關鍵字最大(最小)的元素。

1. 若array[0,...,n-1]表示一顆完全二叉樹的順序儲存模式,則雙親節點指標和孩子結點指標之間的內在關係如下:

  任意一節點指標 i:父節點:i==0 ? null : (i-1)/2

            左孩子:2*i + 1

            右孩子:2*i + 2

2. 堆的定義:n個關鍵字序列array[0,...,n-1],當且僅當滿足下列要求:(0 <= i <= (n-1)/2)

      ① array[i] <= array[2*i + 1] 且 array[i] <= array[2*i + 2]; 稱為小根堆;

      ② array[i] >= array[2*i + 1] 且 array[i] >= array[2*i + 2]; 稱為大根堆;

3. 建立大根堆:

  n個節點的完全二叉樹array[0,...,n-1],最後一個節點n-1是第(n-1-1)/2個節點的孩子。對第(n-1-1)/2個節點為根的子樹調整,使該子樹稱為堆。

  對於大根堆,調整方法為:若【根節點的關鍵字】小於【左右子女中關鍵字較大者】,則交換。

  之後向前依次對各節點((n-2)/2 - 1)~ 0為根的子樹進行調整,看該節點值是否大於其左右子節點的值,若不是,將左右子節點中較大值與之交換,交換後可能會破壞下一級堆,於是繼續採用上述方法構建下一級的堆,直到以該節點為根的子樹構成堆為止。

  反覆利用上述調整堆的方法建堆,直到根節點。

4.堆排序:(大根堆)

  ①將存放在array[0,...,n-1]中的n個元素建成初始堆;

  ②將堆頂元素與堆底元素進行交換,則序列的最大值即已放到正確的位置;

  ③但此時堆被破壞,將堆頂元素向下調整使其繼續保持大根堆的性質,再重複第②③步,直到堆中僅剩下一個元素為止。

堆排序演算法的效能分析:

  空間複雜度:o(1);

  時間複雜度:建堆:o(n),每次調整o(log n),故最好、最壞、平均情況下:o(n*logn);

  穩定性:不穩定

建立大根堆的方法:

 1     //構建大根堆:將array看成完全二叉樹的順序儲存結構
 2     private int[] buildMaxHeap(int[] array){
 3         //從最後一個節點array.length-1的父節點(array.length-1-1)/2開始,直到根節點0,反覆調整堆
 4         for(int i=(array.length-2)/2;i>=0;i--){ 
 5             adjustDownToUp(array, i,array.length);
 6         }
 7         return array;
 8     }
 9     
10     //將元素array[k]自下往上逐步調整樹形結構
11     private void adjustDownToUp(int[] array,int k,int length){
12         int temp = array[k];   
13         for(int i=2*k+1; i<length-1; i=2*i+1){    //i為初始化為節點k的左孩子,沿節點較大的子節點向下調整
14             if(i<length && array[i]<array[i+1]){  //取節點較大的子節點的下標
15                 i++;   //如果節點的右孩子>左孩子,則取右孩子節點的下標
16             }
17             if(temp>=array[i]){  //根節點 >=左右子女中關鍵字較大者,調整結束
18                 break;
19             }else{   //根節點 <左右子女中關鍵字較大者
20                 array[k] = array[i];  //將左右子結點中較大值array[i]調整到雙親節點上
21                 k = i; //【關鍵】修改k值,以便繼續向下調整
22             }
23         }
24         array[k] = temp;  //被調整的結點的值放人最終位置
25     }    

堆排序:

 1     //堆排序
 2     public int[] heapSort(int[] array){
 3         array = buildMaxHeap(array); //初始建堆,array[0]為第一趟值最大的元素
 4         for(int i=array.length-1;i>1;i--){  
 5             int temp = array[0];  //將堆頂元素和堆低元素交換,即得到當前最大元素正確的排序位置
 6             array[0] = array[i];
 7             array[i] = temp;
 8             adjustDownToUp(array, 0,i);  //整理,將剩餘的元素整理成堆
 9         }
10         return array;
11     }

刪除堆頂元素(即序列中的最大值):先將堆的最後一個元素與堆頂元素交換,由於此時堆的性質被破壞,需對此時的根節點進行向下調整操作。

1     //刪除堆頂元素操作
2     public int[] deleteMax(int[] array){
3         //將堆的最後一個元素與堆頂元素交換,堆底元素值設為-99999
4         array[0] = array[array.length-1];
5         array[array.length-1] = -99999;
6         //對此時的根節點進行向下調整
7         adjustDownToUp(array, 0, array.length);
8         return array;
9     }

對堆的插入操作:先將新節點放在堆的末端,再對這個新節點執行向上調整操作。

假設陣列的最後一個元素array[array.length-1]為空,新插入的結點初始時放置在此處。

 1     //插入操作:向大根堆array中插入資料data
 2     public int[] insertData(int[] array, int data){
 3         array[array.length-1] = data; //將新節點放在堆的末端
 4         int k = array.length-1;  //需要調整的節點
 5         int parent = (k-1)/2;    //雙親節點
 6         while(parent >=0 && data>array[parent]){
 7             array[k] = array[parent];  //雙親節點下調
 8             k = parent;
 9             if(parent != 0){
10                 parent = (parent-1)/2;  //繼續向上比較
11             }else{  //根節點已調整完畢,跳出迴圈
12                 break;
13             }
14         }
15         array[k] = data;  //將插入的結點放到正確的位置
16         return array;
17     }

測試:

 1     public void toString(int[] array){
 2         for(int i:array){
 3             System.out.print(i+" ");
 4         }
 5     }
 6     
 7     public static void main(String args[]){
 8         HeapSort hs = new HeapSort();
 9         int[] array = {87,45,78,32,17,65,53,9,122};
10         System.out.print("構建大根堆:");
11         hs.toString(hs.buildMaxHeap(array));
12         System.out.print("\n"+"刪除堆頂元素:");
13         hs.toString(hs.deleteMax(array));
14         System.out.print("\n"+"插入元素63:");
15         hs.toString(hs.insertData(array, 63));
16         System.out.print("\n"+"大根堆排序:");
17         hs.toString(hs.heapSort(array));    
18     }
1 構建大根堆:122 87 78 45 17 65 53 9 32 
2 刪除堆頂元素:87 45 78 32 17 65 53 9 -99999 
3 插入元素63:87 63 78 45 17 65 53 9 32 
4 大根堆排序:9 17 32 45 53 63 65 78 87 

相關推薦

Java實現排序

  堆排序是一種樹形選擇排序方法,它的特點是:在排序的過程中,將array[0,...,n-1]看成是一顆完全二叉樹的順序儲存結構,利用完全二叉樹中雙親節點和孩子結點之間的內在關係,在當前無序區中選擇關鍵字最大(最小)的元素。 1. 若array[0,...,n-1]表示一顆完全二叉樹的順序儲存模式,則雙親

Java 排序及小

整理網上的最大堆及最小堆程式碼 public abstract class Sorter { public abstract void sort(int[] array); } public class HeapSorter extends

排序演算法——排序、小頂

堆排序的思想這裡就先不講了,以後有時間再補上,下面是分別採用大頂堆和小頂堆實現的堆排序。 注意:下面例子中排序的數字是{1,2,5,3,6,4,9,7,8}。 大頂堆方式 #include &

java實現常見排序選擇,冒泡,插入,快速,希爾,

選擇排序定義一個的標誌位temp,預設為比較的第一個數的下標,分別與後面的數進行比較,若比比較的數字大,則把該數的下標賦給temp,迴圈一次結束後判斷temp的值,若temp值跟第一個數的下標不一樣,則

演算法-一步步教你如何用c語言實現排序非遞迴

看了左神的堆排序,覺得思路很清晰,比常見的遞迴的堆排序要更容易理解,所以自己整理了一下筆記,帶大家一步步實現堆排序演算法 首先介紹什麼是大根堆:每一個子樹的最大值都是子樹的頭結點,即根結點是所有結點的最大值 堆排序是基於陣列和二叉樹思想實現的(二叉樹是腦補結構,實際是陣列) 堆排序過程 1、陣列建

使用java實現快速排序我認為是最簡單最容易理解的版本

一切都在程式碼和註釋之中。複製貼上就能跑,邊跑邊看才是最愉快的。 所以,話不多說,放碼過來。   public class QuickSort { public static void main(String[] args) { int x[]={6,1,2,7,9,1

Java實現--歸併排序遞迴

《Java資料結構和演算法》如此描述分治演算法: 把一個大問題分成兩個相對來說更小的問題,並且分別解決每一個小問題,對每一個小問題的解決方案是一樣的:把每個小問題分成兩個更小的問題,並且解決它們。這個過程一直持續小去知道達到易於求解的基值情況,就不用再繼續分了。 時間複雜度:

排序最小C++

堆分為大根堆(最大堆)和小根堆(最小堆),堆排序就是二叉堆的升級版,實際上是一棵完全二叉樹 不同的是這棵二叉樹裡每個節點保證父節點都小於孩子節點 最後進行堆排序,將堆頂最小的節點(第一個)與最後一個節點(最大的節點)進行交換,對剩下的進行調節,令其滿足最小堆 #incl

Java實現插入排序

原理:每一步將一個待排序的記錄,插入到前面已經排好序的有序序列中去,直到插完所有元素為止。 思想:想必你肯定打過撲克牌吧,在一張一張揭牌的時候,是不是每次揭一張牌將其插入到其他已經有序的牌中的適當位置,如果你沒有這個經歷,趕緊約一波小夥伴,鬥一把。與選擇排序一樣,把要排序的

java實現歸併排序思想與實現

歸併排序歸併排序是採用分治法的一個非常典型的應用。歸併排序的思想就是先遞迴分解陣列,再合併陣列。將陣列分解最小之後,然後合併兩個有序陣列,基本思路是比較兩個陣列的最前面的數,誰小就先取誰,取了後相應的指標就往後移一位。然後再比較,直至一個數組為空,最後把另一個數組的剩餘部分複

一種簡單的用java實現快速排序Quicksort

1,快速排序(Quicksort)是對氣泡排序的一種改進。對資料量越大,資料分佈越混亂的,一般認為是效能最好的。快排是分治思想的一種體現,把大的問題細化成小問題,把小問題細化成更小的問題,最終把問題縮小到一定規模內,可解決。 2,快排演算法思路就是,先取一個數作為關鍵資料(key一般

Java實現快速排序分治法

<span style="font-size:18px;">package com.alibaba; public class QuickSortTest { public stati

排序最小--【演算法導論】

堆排序的思想在堆排序(最大堆)已做說明,故不再贅述; 總之,思想就是首先進行建堆,由於這是最小堆,故而必須保證父節點都小於孩子節點,若不滿足條件,則進行調節; 最後進行堆排序,不斷將最小的提取出來,並對剩下的進行調節,使之滿足最小堆; 故而將最大堆中的判斷父節點與孩子大小部

排序演算法Java實現——選擇排序直接選擇排序

比較排序程式碼: /*@(#)chooseSort.java 2017-4-22 * Copy Right 2017 Bank of Communications Co.Ltd. * A

排序,小頂

一如既往,先上詳細的過程圖。 應用場景 比如求10億個數中的最大的前10個數,時時構建只有10個元素的小頂堆,如果比堆頂小,則不處理;如果比堆頂大,則替換堆頂,然後依次下沉到適當的位置。 比如求10億個數中的最小的前10個數,時時構建只有10個元素的大頂堆,如果比堆頂大

java實現插入排序思路和實現

插入排序(英語:Insertion Sort)是一種簡單直觀的排序演算法。它的工作原理是通過構建有序序列,對於未排序資料,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在實現上,在從後向前掃描過程中,需要反覆把已排序元素逐步向後挪位,為最新元素提供插入空間。插入排序

Java實現氣泡排序

原理:每次比較兩個相鄰的元素,將較大的元素交換至右端。 思路:每次氣泡排序操作都會將相鄰的兩個元素進行比較,看是否滿足大小關係要求,如果不滿足,就交換這兩個相鄰元素的次序,一次冒泡至少讓一個元素移動到它應該排列的位置,重複N次,就完成了氣泡排序。 通過一個圖來簡單理解一下

Java實現快速排序快排

快速排序是氣泡排序的改進版,也是最好的一種內排序,在很多面試題中都會出現,也是作為程式設計師必須掌握的一種排序方法。 快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一部分的所

算法——python實現快速排序二分法思想

append exc microsoft 部分 input temp style 數字 快速排序 實現思路   將所需要的數字存入一個列表中 首先,設置將最左側的那個數設置為基準數,在列表中索引為0 然後設置兩個移動位(用於比較),分別為最左邊和最右邊 然後最右邊那位向左

java實現數字反轉逆序輸出

要求:輸入一個整數,將這個數字逆序輸出(數字反轉) 例如:輸入3251,需輸出1523 package com.number.test; import java.util.Scanner; /**