堆排序
難度:★★★★☆
基本思想
二叉堆:
叉堆有兩種:最大堆和最小堆。最大堆:父結點的鍵值總是大於或等於任何一個子節點的鍵值;最小堆:父結點的鍵值總是小於或等於任何一個子節點的鍵值。
數組表示二叉堆:
對於數組按照二叉樹從左向右,從上到下依次排列,如圖:
[0,1,2,3,4,5,6,7,8]
- 堆的根節點(root)爲A[0];
- 對這個堆中i節點(從0開始);
- 父節i的左節點,數組對應A[2*i+1];
- 父節i的右節點,數組對應A[2*i+2];
- 反過來知道某個節點數組下標爲i,則它的父節點爲(i-1)/2
利用二叉堆排序:
1.將A構建成一個最大堆(符合max-heap property,也就是根節點最大);
2.取出根節點;第一位與最後一位交換,同時數組長度減1,對減1的數組進行下一輪排序
3.將剩下的數組元素在建成一個最大二叉堆,返回第2步,直到所有元素都被取光。
算法圖解
建成一個最大堆
程序實現
import java.util.Arrays;
import java.util.Random;
/**
* Created by android on 19-6-24.
*/
public class MaxHeap {
protected int A[];
protected int heapsize;
/**
* @param i,父節點,需要調整該節點與其子節點的值,使得保證任何何一個節點在任何情況下的值都不會超過它的父親節點,A[Parent]≥A[i]
*/
protected void maxHeapify(int i) {
int l = 2 * i + 1;
int r = 2 * i + 2;
int largest = i;
if (l <= heapsize - 1 && A[l] > A[i]) {
largest = l;
}
if (r <= heapsize - 1 && A[r] > A[largest]) {
largest = r;
}
if (largest != i) {
int temp = A[i];
// 父節點比其的一個子節點小,交換其值
A[i] = A[largest];
A[largest] = temp;
//因爲子節點交換爲一個小值,需要與子節點的子節點進行比較,保證任何何一個節點在任何情況下的值都不會超過它的父親節點
maxHeapify(largest);
}
}
//節點i所對應的父節點
protected int parent(int i) {
return (i - 1) / 2;
}
public void buildMaxHeap(int[] A) {
this.A = A;
this.heapsize = A.length;
for (int i = parent(heapsize - 1); i >= 0; i--)
maxHeapify(i);
}
public void heapsort(int[] A) {
buildMaxHeap(A);
int step = 1;
for (int i = A.length - 1; i > 0; i--) {
System.out.println("Step: " + (step++) + Arrays.toString(A));
int temp = A[i];
A[i] = A[0];
A[0] = temp;
heapsize--;
maxHeapify(0);
}
}
public static void main(String[] args) {
//a sample input
Random random = new Random();
int[] A = new int[18];
for (int i = 0; i < A.length; i++) {
A[i] = random.nextInt(10);
}
System.out.println("Input: " + Arrays.toString(A));
MaxHeap maxhp = new MaxHeap();
maxhp.heapsort(A);
System.out.println("Output: " + Arrays.toString(A));
}
}
排序算法穩定性
如果一個無序的序列裏有兩個相等的數據,在排序之後與之前的前後關係一定一樣,那麼就是穩定的排序,反正不穩定。堆排序不穩定