參考資料算法
二叉堆:一個堆有序的徹底二叉樹, 叫作二叉堆。後端
/** * @param a 表示堆的數組 * @param k 堆中的節點位置 */ private void swim (int [] a, int k) { while(k>1&&a[k]>a[k/2]){ // 當該結點存在父節點,且大於父節點的時候 exchange(a, k, k/2); // 交換它和它的父節點值 k = k/2; // 取得父節點的位置 } }
/** * @param a 表示堆的數組 * @param k 堆中的節點位置 * @param N 堆中節點總數 */ private void sink (int [] a, int k, int N) { while(2*k<=N) { // 當該節點存在至少一個子節點的時候 int j = 2*k; // 取得左兒子的位置 if(j<N&&a[j]<a[j+1]) { j++; } // 取得左兒子和右兒子中的較大者 if(a[k]<a[j]) { // 當該節點的值小於較大的左兒子的時候 exchange(a, k, j); // 交換它和該兒子節點的值 k = j; // 取得該兒子節點的位置 } else { break; } } }
/** * 向堆中插入值 * @param v 要插入的值 */ public void insert (int v) { a[N+1]= v; // 元素被放入堆的最末端成爲新節點 N++; // 增長堆的大小 swim(N); // 對末端節點進行上浮操做使其有序 }
/** * 刪除堆中的最大值, 而且將其返回 * @return 堆節點最大值 */ public int delMax () { if(isEmpty()) return 0; // 當堆爲空時, 返回 int max = a[1]; // 取得堆中根節點(最大值) exchange(a, 1, N); // 交換根節點和末端節點(最後一個元素)的值 N--; // 減小堆的大小 (「刪除」完畢) sink(1); // 下沉操做,讓剛放上根節點的新元素下沉到合適的位置 return max; }
public class Heap { /** * N: 記錄二叉堆中的節點總數 * a: 容納二叉堆節點的數組,從a[0]開始存放 */ private int N = 0; private int [] a; /** * @param maxN 建立堆中節點的總數 */ public Heap (int maxN) { a = new int [maxN+1]; } private static void exchange(int [] a , int i, int j) { int temp = a[i]; a[i] = a[j]; a[j] = temp; } /** * 上浮操做 * @param k 堆中的節點位置 */ private void swim (int k) { while(k>1&&a[k]>a[k/2]){ // 當該結點存在父節點,且大於父節點的時候 exchange(a, k, k/2); // 交換它和它的父節點值 k = k/2; // 取得父節點的位置 } } /** * 下沉操做 * @param k 堆中的節點位置 */ private void sink ( int k ) { while(2*k<=N) { // 當該節點存在至少一個子節點的時候 int j = 2*k; // 取得左兒子的位置 if(j<N&&a[j]<a[j+1]) { j++; } // 取得左兒子和右兒子中的較大者 if(a[k]<a[j]) { // 當該節點的值小於較大的左兒子的時候 exchange(a, k, j); // 交換它和該兒子節點的值 k = j; // 取得該兒子節點的位置 } else { break; } } } /** * 向堆中插入值 * @param v 要插入的值 */ public void insert (int v) { a[N+1]= v; // 元素被放入堆的最末端成爲新節點 N++; // 增長堆的大小 swim(N); // 對末端節點進行上浮操做使其有序 } /** * 刪除堆中的最大值, 而且將其返回 * @return 堆節點最大值 */ public int delMax () { if(isEmpty()) return 0; // 當堆爲空時, 返回 int max = a[1]; // 取得堆中根節點(最大值) exchange(a, 1, N); // 交換根節點和末端節點(最後一個元素)的值 N--; // 減小堆的大小 (「刪除」完畢) sink(1); // 下沉操做,讓剛放上根節點的新元素下沉到合適的位置 return max; } /** * 判斷堆數組是否爲空 */ public boolean isEmpty() { return N == 0; } }
public class Test { public static void main (String [] args) {
// 建立一個能容納10個元素的堆 Heap heap = new Heap(10); int [] array = {2,6,3,9,1,5,4,3,0,2}; // 將數組元素依次放入堆中 for(int i =0; i<array.length;i++) { heap.insert(array[i]); } // 依次刪除堆中的最大元素並輸出 for(int i =0; i<array.length;i++) { System.out.println(heap.delMax()); } } }
9 6 5 4 3 3 2 2 1 0
int N = a.length; // 取得節點總數 for(int i=N/2;i>0; i--) { sink(a, i, N); // 對全部父節點,從最後一個父節點到根節點,依次下沉排序 }
把構造完畢(實現堆有序)以後,咱們就要將「堆有序」的數組轉化爲「有序」的數組,這一階段被稱爲下沉排序數組
while(N>1){ exchange(a, 1, N); // 將數組中最大的元素放到數組後端 N--; // 將最大的節點元素移出堆 sink(a, 1, N); // 下沉操做,再次實現堆有序 }
如圖所示:less
/** * 堆排序方法 * @param a 待排序數組 */ public static void sort(int [] a) { // 堆的構造階段 int N = a.length; // 取得節點總數 for(int i=N/2;i>0; i--) { sink(a, i, N); // 對全部父節點,從最後一個父節點到根節點,依次下沉排序 } // 到這裏數組已經徹底堆有序
// 下沉排序階段 while(N>1){ exchange(a, 1, N); // 將數組中最大的元素放到數組後端 N--; // 將最大的節點元素移出堆 sink(a, 1, N); // 下沉操做,再次實現堆有序 } }
/** * 交換兩個數組元素的值 * 注意! 不一樣於通常的exchange, 這裏的i和j要減1! */ private static void exchange(int [] a , int i, int j) { int temp = a[i-1]; a[i-1] = a[j-1]; a[j-1] = temp; } /** * 比較i和j下標的數組元素的大小 * 注意! 不一樣於通常的less, 這裏的i和j要減1! */ private static boolean less (int [] a, int i, int j) { return a[i-1]-a[j-1]<0 ? true : false; }
public class HeapSort { /** * 交換兩個數組元素的值 * 注意! 不一樣於通常的exchange, 這裏的i和j要減1! */ private static void exchange(int [] a , int i, int j) { int temp = a[i-1]; a[i-1] = a[j-1]; a[j-1] = temp; } /** * 比較i和j下標的數組元素的大小 * 注意! 不一樣於通常的less, 這裏的i和j要減1! */ private static boolean less (int [] a, int i, int j) { return a[i-1]-a[j-1]<0 ? true : false; } /** * 下沉操做 * @param a 待排序數組 * @param k 堆中的節點位置 * @param N 堆中的節點總數 */ private static void sink (int [] a, int k, int N) { while(2*k<=N) { // 當該節點存在至少一個子節點的時候 int j = 2*k; // 取得左兒子的位置 if(j<N&&less(a, j, j+1)) { j++; } // 取得左兒子和右兒子中的較大者 if(less(a, k, j)) { // 當該節點的值小於較大的左兒子的時候 exchange(a, k, j); // 交換它和該兒子節點的值 k = j; // 取得該兒子節點的位置 } else { break; } } } /** * 堆排序方法 * @param a 待排序數組 */ public static void sort(int [] a) { // 堆的構造階段 int N = a.length; // 取得節點總數 for(int i=N/2;i>0; i--) { sink(a, i, N); // 對全部父節點,從最後一個父節點到根節點,依次下沉排序 } // 到這裏數組已經徹底堆有序 // 下沉排序階段 while(N>1){ exchange(a, 1, N); // 將數組中最大的元素放到數組後端 N--; // 將最大的節點元素移出堆 sink(a, 1, N); // 下沉操做,再次實現堆有序 } } }
public class Test { public static void main (String [] args) { int [] array = {3,0,8,9,1,5,4,2,7,1,2}; HeapSort.sort(array); for(int i=0;i<array.length;i++) { System.out.println(array[i]); } } }
0 1 1 2 2 3 4 5 7 8 9