HeapSort.java
建立大根堆,然后交换堆顶元素和尾部元素,heapSize减1,每次交换完对堆顶(索引为0)的元素进行下滤操作,使其恢复堆的性质。直到heapSize == 0时退出循环
本质:
你仔细想一想,是不是和循环删除堆顶元素很像,只不过不是删除,而是直接循环将堆顶元素保存在数组尾部
package mj.sort.cmp;
import mj.sort.Sort;
public class HeapSort<T extends Comparable<T>> extends Sort<T> {
private int heapSize;
@Override
protected void sort() {
// 原地建堆
heapSize = array.length;
for (int i = (heapSize >> 1) - 1; i >= 0; i--) {
siftDown(i);
}
while (heapSize > 1) {
// 交换堆顶元素和尾部元素
swap(0, --heapSize);
// 对0位置进行siftDown(恢复堆的性质)
siftDown(0);
}
}
private void siftDown(int index) {
T element = array[index];
int half = heapSize >> 1;
while (index < half) { // index必须是非叶子节点
// 默认是左边跟父节点比
int childIndex = (index << 1) + 1;
T child = array[childIndex];
int rightIndex = childIndex + 1;
// 右子节点比左子节点大
if (rightIndex < heapSize &&
cmp(array[rightIndex], child) > 0) {
child = array[childIndex = rightIndex];
}
// 大于等于子节点
if (cmp(element, child) >= 0) break;
array[index] = child;
index = childIndex;
}
array[index] = element;
}
}
Sort.java
package mj.sort;
import mj.Student;
import mj.sort.cmp.SelectionSort;
import mj.sort.cmp.ShellSort;
import java.text.DecimalFormat;
@SuppressWarnings("unchecked")
public abstract class Sort<T extends Comparable<T>> implements Comparable<Sort<T>> {
protected T[] array;
private int cmpCount;
private int swapCount;
private long time;
private DecimalFormat fmt = new DecimalFormat("#.00");
public void sort(T[] array) {
if (array == null || array.length < 2) return;
this.array = array;
long begin = System.currentTimeMillis();
sort();
time = System.currentTimeMillis() - begin;
}
@Override
public int compareTo(Sort<T> o) {
int result = (int)(time - o.time);
if (result != 0) return result;
result = cmpCount - o.cmpCount;
if (result != 0) return result;
return swapCount - o.swapCount;
}
protected abstract void sort();
/*
* 返回值等于0,代表 array[i1] == array[i2]
* 返回值小于0,代表 array[i1] < array[i2]
* 返回值大于0,代表 array[i1] > array[i2]
*/
protected int cmp(int i1, int i2) {
cmpCount++;
return array[i1].compareTo(array[i2]);
}
protected int cmp(T v1, T v2) {
cmpCount++;
return v1.compareTo(v2);
}
protected void swap(int i1, int i2) {
swapCount++;
T tmp = array[i1];
array[i1] = array[i2];
array[i2] = tmp;
}
@Override
public String toString() {
String timeStr = "耗时:" + (time / 1000.0) + "s(" + time + "ms)";
String compareCountStr = "比较:" + numberString(cmpCount);
String swapCountStr = "交换:" + numberString(swapCount);
String stableStr = "稳定性:" + isStable();
return "【" + getClass().getSimpleName() + "】\n"
+ stableStr + " \t"
+ timeStr + " \t"
+ compareCountStr + "\t "
+ swapCountStr + "\n"
+ "------------------------------------------------------------------";
}
private String numberString(int number) {
if (number < 10000) return "" + number;
if (number < 100000000) return fmt.format(number / 10000.0) + "万";
return fmt.format(number / 100000000.0) + "亿";
}
private boolean isStable() {
if (this instanceof RadixSort) return true;
if (this instanceof CountingSort) return true;
if (this instanceof ShellSort) return false;
if (this instanceof SelectionSort) return false;
Student[] students = new Student[20];
for (int i = 0; i < students.length; i++) {
students[i] = new Student(i * 10, 10);
}
sort((T[]) students);
for (int i = 1; i < students.length; i++) {
int score = students[i].score;
int prevScore = students[i - 1].score;
if (score != prevScore + 10) return false;
}
return true;
}
}