堆排序是使用二叉樹模型,建立最大堆或最小堆,將最大值或最小值上浮,降低遍歷次數,增加排序效率的一種解決方法。
由於堆排序時使用的是完全二叉模型,所以可以使用數組進行表示。
在使用堆排序時,需要使用到完全二叉樹的一些公式,如父節點n/2-1,左子節點2i+1,右子節點2i+2,葉子節點(>size/2)等。具體見代碼。
1、首先定義堆模型的一些常用操作接口。
package cn.dream.sort;
public interface IHeapSort {
/**
* 獲取父節點的位置
* 完全二叉樹父節點位置在(n-1)/2處
* @param i
* @return
*/
int getParent(int i);
/**
* 獲取左子位置
* 完全二叉樹左子節點在2*i+1處
* @param i
* @return
*/
int getLeftChild(int i);
/**
* 獲取右子位置
* 完全二叉樹右子節點在左子節點的後面(2*i+1)+1
* @param i
* @return
*/
int getRightChild(int i);
/**
* 建堆
* 從n/2-1處開始調整樹結構,因爲從n/2處都是葉子節點,不需要調整
* @param a
* @param size
*/
int[] buildHeap(int[] a, int size);
/**
* 調整堆
* 通過對堆的調整,使其滿足堆結構的要求,最大值上浮或最小值上浮。
* 對於任一節點進行調整時:
* 1、最大堆:如果該節點比(左右子節點最大值)小,交換該節點和最大值位置,然後調整樹
* 2、最小堆:如果該節點比(左右子節點最小值)大,交換該節點和最小值位置,然後調整樹
* @param a
* @param i
* @param size
*/
int[] adjustHeap(int[] a, int i, int size);
/**
* 堆排序
* 1、最小堆:
* 方法一:執行遍歷{將根節點(min)取出,構建樹}
* 方法二:執行遍歷{將根節點(min)和最後一個節點(數組最後一位)交換,將參與構建的數組長度-1(移動size的index),重新構建樹結構},最後倒序輸出
* 2、最大堆:執行遍歷{將根節點(max)和最後一個節點(數組最後一位)交換,將參與構建的數組長度-1(移動size的index),重新構建樹結構}
* @param a
* @param size
*/
int[] sortHeap(int[] a, int size);
}
最小堆
package cn.dream.sort;
import java.util.Arrays;
public class MinHeapSortImpl implements IHeapSort {
@Override
public int getParent(int i) {
return (int) (i - 1) / 2;
}
@Override
public int getLeftChild(int i) {
return 2 * i + 1;
}
@Override
public int getRightChild(int i) {
return 2 * i + 2;
}
@Override
public int[] buildHeap(int[] a, int size) {
for (int i = (size - 2) / 2; i >= 0; i--) {
adjustHeap(a, i, size);
}
return a;
}
@Override
public int[] adjustHeap(int[] a, int i, int size) {
int min = i;
int temp = a[i];
int left = getLeftChild(i);
int right = getRightChild(i);
if (left < size && a[left] < temp) {
min = left;
}
if (right < size && a[right] < a[min]) {
min = right;
}
if (min != i) {
a[i] = a[min];
a[min] = temp;
adjustHeap(a, min, size);
}
return a;
}
@Override
public int[] sortHeap(int[] a, int size) {
int[] b = new int[a.length];
int i = 0;
while(size>0) {
b[i] = a[0];
a[0] = a[size - 1];
--size;
adjustHeap(a, 0, size);
i++;
}
return b;
}
public static void main(String[] args) {
int[] arr = { 53, 4, 24, 47, 41, 97, 13, 83, 12, 35, 11, 15, 41, 18,
68, 49, 36, 52, 9, 45, 0, 38, 36, 82, 76, 22, 44, 35, 34, 81,
94, 70, 88, 30, 42, 45, 55, 75, 93, 57, 74, 0, 77, 64, 93, 58,
15, 62, 13, 49, 60, 21, 3, 66, 15, 74, 48, 96, 52, 56, 63, 73,
85, 44, 39, 42, 98, 38, 17, 81, 7, 60, 86, 79, 63, 66, 17, 78,
78, 90, 23, 92, 79, 21, 80, 71, 6, 70, 59, 25, 41, 11, 64, 60,
62, 51, 93, 46, 18, 31 };
long startTime = System.currentTimeMillis();
IHeapSort heapSort = new MinHeapSortImpl();
System.out.println("測試最小堆的根節點是否最小值:");
heapSort.buildHeap(arr, arr.length);
System.out.println("root is:" + arr[0]);
System.out.println("測試最小堆是否已經排序:");
System.out.println(Arrays.toString(arr));
System.out.println("排序:");
int[] heap = heapSort.sortHeap(arr, arr.length);
System.out.println(Arrays.toString(heap));
System.out.println((System.currentTimeMillis() - startTime) + "ms");
}
}
最大堆
package cn.dream.sort;
import java.util.Arrays;
public class MaxHeapSortImpl implements IHeapSort {
@Override
public int getParent(int i) {
return (int) (i - 1) / 2;
}
@Override
public int getLeftChild(int i) {
return 2 * i + 1;
}
@Override
public int getRightChild(int i) {
return 2 * i + 2;
}
@Override
public int[] buildHeap(int[] a, int size) {
for (int i = (size - 2) / 2; i >= 0; i--) {
adjustHeap(a, i, size);
}
return a;
}
@Override
public int[] adjustHeap(int[] a, int i, int size) {
int largest = i;
int temp = a[i];
int left = getLeftChild(i);
int right = getRightChild(i);
if (left < size && a[left] > temp) {
largest = left;
}
if (right < size && a[right] > a[largest]) {
largest = right;
}
if (largest != i) {
a[i] = a[largest];
a[largest] = temp;
adjustHeap(a, largest, size);
}
return a;
}
@Override
public int[] sortHeap(int[] a, int size) {
// buildHeap(a, size);
int temp;
for (int i = size - 1; i >= 0; i--) {
temp = a[0];
a[0] = a[i];
a[i] = temp;
adjustHeap(a, 0, i);
}
return a;
}
public static void main(String[] args) {
int[] arr = { 53, 4, 24, 47, 41, 97, 13, 83, 12, 35, 11, 15, 41, 18,
68, 49, 36, 52, 9, 45, 0, 38, 36, 82, 76, 22, 44, 35, 34, 81,
94, 70, 88, 30, 42, 45, 55, 75, 93, 57, 74, 0, 77, 64, 93, 58,
15, 62, 13, 49, 60, 21, 3, 66, 15, 74, 48, 96, 52, 56, 63, 73,
85, 44, 39, 42, 98, 38, 17, 81, 7, 60, 86, 79, 63, 66, 17, 78,
78, 90, 23, 92, 79, 21, 80, 71, 6, 70, 59, 25, 41, 11, 64, 60,
62, 51, 93, 46, 18, 31 };
long startTime = System.currentTimeMillis();
IHeapSort heapSort = new MaxHeapSortImpl();
System.out.println("測試最大堆的根節點是否最大值:");
heapSort.buildHeap(arr, arr.length);
System.out.println("root is:" + arr[0]);
System.out.println("測試最大堆的順序是否爲倒序:");
System.out.println(Arrays.toString(arr));
System.out.println("排序:");
heapSort.sortHeap(arr, arr.length);
System.out.println(Arrays.toString(arr));
System.out.println((System.currentTimeMillis() - startTime) + "ms");
}
}
更多排序,,參考這位的http://blog.csdn.net/han_xiaoyang/article/details/12163251