1 基本介紹
堆數據結構是一種數組對象,它可以被視爲一顆完全二叉樹。堆的訪問可以通過三個函數來進行即,
parent(i)
return floor(i/2);
left(i)
return 2i;
right(i)
return 2i + 1;
left操作可以通過一步左移操作完成,right操作可以通過左移並在地位+1實現,parent操作則可以通過把i右移一位得到。在實現中通常會使用宏或者內聯函數來實現這三個操作。
二叉堆有兩種,最大堆和最小堆。對於最大堆有
A[i] >= A[left(i)] && A[i] >= A[right(i)]
最小堆則是
A[i] <= A[left(i)] && A[i]<= A[right(i)]
最堆排序算法中,使用的是最大堆,最小堆通常在構造優先隊列時使用。堆可以被看成是一棵樹,結點在堆中的高度定義爲從本結點到葉子的最長簡單下降路徑上邊的數目;定義堆的高度爲樹根的高度。
2 原理部分
下面就關於堆的幾個基本函數做一下說明:
maxHeapify(),運行時間爲O(lgn)用於保持堆的性質;
bulidMaxHeap(),以線性時間運行,可以在無序的輸入數組基礎上構造出最大堆;
heapSort(),運行時間爲O(nlgn),對一個數組原地進行排序。
2.1 保持堆的性質
maxHeapify(A,i)
l <- left(i)
r <- right(i)
if l <= heap-size[A] and A[l] > A[i]
then largest <- l
else largest <- i
if r <= heap-size[A] and A[r] > A[largest]
then largest <- r
if largest != i
then exchange A[i] <-> A[largest] // 交換i和比它大的那個子結點
maxHeapify(A,largest); // 遞歸調用
2.2 建堆
buildMaxHeap(A)
heap-size[A] <- length[A]
for i <- floor(length[A] / 2) downto 1
do max-heapify(A,i)
2.3 堆排序算法
heapSort(A)
buildMaxHeap(A)
for i <- length[A] downto 2
do exchange A[1] <-> A[i]
heap-size[A] <- heap-size[A] - 1
maxHeapify(A,1)
雖然堆排序算法是一個很nice的算法,但是在實際應用中,快速排序的一個好的實現往往優於堆排序。
3 java實現
3.1 數據結構
import java.io.Serializable;
/**
* Date: 2014/8/17
* Time: 16:02
*/
public class Heap implements Serializable{
private int heapLength;
private int [] data;
public int getHeapLength() {
return heapLength;
}
public void setHeapLength(int heapLength) {
this.heapLength = heapLength;
}
public int[] getData() {
return data;
}
public void setData(int[] data) {
this.data = data;
}
}
3.2 操作類
/**
* Created with IntelliJ IDEA.
* Date: 2014/8/17
* Time: 15:39
*/
public class HeapSort {
public final static int getLeft(int i) {
return i << 1;
}
public final static int getRight(int i) {
return (i << 1) + 1;
}
public final static int getParent(int i) {
return i >> 1;
}
/**
* 保持堆的性質
*
* @param heap
* @param i
*/
public static void maxHeapify(Heap heap, int i) {
if (null == heap || null == heap.getData() || heap.getData().length <= 0 || i < 0)
return;
int l = getLeft(i);
int r = getRight(i);
int largest = 0;
if (l < heap.getHeapLength() && heap.getData()[l] > heap.getData()[i])
largest = l;
else
largest = i;
if (r < heap.getHeapLength() && heap.getData()[r] > heap.getData()[largest])
largest = r;
if (largest != i) {
int tmp = heap.getData()[i];
heap.getData()[i] = heap.getData()[largest];
heap.getData()[largest] = tmp;
maxHeapify(heap, largest);
}
}
/**
* 建立最大堆
*
* @param array
* @return
*/
public static Heap bulidMaxHeap(int[] array) {
if (null == array || array.length <= 0)
return null;
Heap heap = new Heap();
heap.setData(array);
heap.setHeapLength(array.length);
for (int i = (array.length >> 1); i >= 0; i--)
maxHeapify(heap, i);
return heap;
}
/**
* 堆排序
*
* @param array
*/
public static void heapSort(int[] array) {
if (null == array || array.length <= 0)
return;
Heap heap = bulidMaxHeap(array);
if (null == heap)
return;
for (int i = heap.getHeapLength() - 1; i > 0; i--) {
int tmp = heap.getData()[0];
heap.getData()[0] = heap.getData()[i];
heap.getData()[i] = tmp;
heap.setHeapLength(heap.getHeapLength() - 1);
maxHeapify(heap, 0);
}
}
}
3.3 測試類
public class Main {
public static void main(String[] args) {
int a[] = {9, 3, 4, 1, 5, 10, 7};
System.out.println("Hello World!");
Sort sort = new Sort();
// sort.bubbleSort(a);
// sort.selectSort(a);
// sort.insertionSort(a);
HeapSort.heapSort(a);
for (int i = 0; i < a.length; i++)
System.out.println(a[i]);
}
}