本文首發於我的博客html
本系列排序包括十大經典排序算法。git
Sort
裏面實現了,交換,大小比較等方法。例如交換兩個值,直接傳入下標就能夠了。其餘的具體排序的類都繼承抽象類Sort
。這樣咱們就能專一於算法自己。/*
* 返回值等於0,表明 array[i1] == array[i2]
* 返回值小於0,表明 array[i1] < array[i2]
* 返回值大於0,表明 array[i1] > array[i2]
*/
protected int cmp(int i1, int i2) {
return array[i1].compareTo(array[i2]);
}
protected int cmp(T v1, T v2) {
return v1.compareTo(v2);
}
protected void swap(int i1, int i2) {
T tmp = array[i1];
array[i1] = array[i2];
array[i2] = tmp;
}
複製代碼
由於本文不是專門講解堆這種數據結構的,主要是講解堆排序算法的。因此這裏只給出堆的一些性質和結論github
2*i+1<=n-1 它的左子節點的索引爲2*i+1
2*i+1>n-1 它沒有左子節點
2*i+2<=n-1 它的右子節點的索引爲2*i+2
2*i+2>n-1 它沒有右子節點
public class HeapSort <T extends Comparable<T>> extends Sort<T>{
private int heapSize;
@Override
protected void sort() {
// 原地建堆 自下而上的下濾
heapSize = array.length;
// heapSize>>1-1 第一個非葉子節點的下標
for (int i = (heapSize>>1)-1; i >=0; i--) {
siftDown(i);
}
while (heapSize>1) {
// 交換堆頂元素和尾部元素
swap(0, heapSize-1);
//堆頂元素最大放到尾部了。下次就不須要考慮這個了。因此size要減1
heapSize--;
// 下濾 維護堆的性質
siftDown(0);
}
}
//讓index位置的元素下濾
private void siftDown(int index) {
// 取出要下濾的座標的值
T element = array[index];
int half = heapSize>>1;
// 第一個葉子節點的索引 == 非葉子節點的數量
// index<第一個葉子節點的索引
// 必須保證index位置是非葉子節點
while (index<half) {
// index的節點有2種狀況
// 1.只有左子節點
// 2.同時有左右子節點
// 默認爲左子節點跟它進行比較
int childIndex = (index<<1)+1;
T child = array[childIndex];
// 右子節點
int rightIndex = childIndex +1;
// 選出左右子節點最大的那個
if (rightIndex<heapSize && cmp(array[rightIndex], child)>0) {
childIndex = rightIndex;
child = array[childIndex];
}
if (cmp(element, child)>=0) {
break;
}
// 將子節點存放到index位置
array[index]= child;
// 從新設置index
index = childIndex;
}
// 將目標值存放到最終的index位置
array[index] = element;
}
}
複製代碼
數據源:從1到20000之間隨機生成10000個數據來測試算法
Integer[] array = Integers.random(10000, 1, 20000);bash
結果以下:數據結構
【HeapSort】 穩定性:false 耗時:0.008s(8ms) 比較次數:23.54萬 交換次數:9999dom
【BubbleSort】 穩定性:true 耗時:0.502s(502ms) 比較次數:4999.50萬 交換次數:2489.42萬ide
【SelectionSort】 穩定性:true 耗時:0.115s(115ms) 比較次數:4999.50萬 交換次數:9999性能
能夠看到堆排序明顯比選擇排序和冒泡排序的性能高不少。測試