1.简介
堆排序是指利用堆这种数据结构所设计的一种排序算法。
2.堆排序中大堆和小堆
大堆:根节点比子节点大
小堆:跟节点比子节点小
3.核心思想
采用大堆的数据结构为例子。
数组转完全二叉树,再把这个完全二叉树构成一个大堆,
将堆顶根节点和末尾节点互换。
把剩下的n-1个元素重新构造成大顶堆(最大值已经换到结尾处,我们不在去考虑,再找剩下n-1个数的最大值)
再次交换堆顶根节点和末尾节点…
重复操作直到最后只剩下一个数
4.步骤
(1).首先构造大堆
(2).把堆顶根节点和末尾节点互换
(3).剩下n-1和节点再次构造大堆
(4).重复操作
5.时间复杂度
nlogn ( n代表有n个数字要被构造为堆顶根节点,logn一棵树的高度,
最坏情况下,每个店都要冒一棵树的高度才能成为堆顶的根节点)
6.代码实现
public class HeapSort {
/*
先说一下堆排序之前需要
构造的一些方法
(1) exchangeElements 数值交换方法
(2) maxHeap 子树构造大堆
(3) buildMaxHeap 建立最大堆
*/
/**
* 堆排序方法开始
*/
public void heapSort(int[] a) {
//数组非法性判断
//只有一个数或者零个数就不用排序了
//空数组也不用
if (a == null || a.length <= 1) {
return;
}
//(1).首先构造大堆
buildMaxHeap(a);
for(int i = a.length -1;i >= 1;i --) {
//(2).把堆顶根节点和末尾节点互换
exchangeElements(a,0,i);
//(3).剩下n-1和节点再次构造大堆
maxHeap(a,i,0);
}
}
private void buildMaxHeap(int[] a) {
//还是判断一下吧 ,万一被别的函数调用了呢
if (a == null || a.length <= 1) {
return;
}
//堆排序的优点体现在这里
//只用遍历所有根节点就可以找出最大值
int half = (a.length - 1)/2;
//这里等于0也是要取的
for(int i = half;i >= 0;i --) {
//从最底层的根节点开始
//调用maxHeap,子树排序
maxHeap(a,a.length,i);
}
}
/*
*length表示可控长度为,有多少节点要来构造大堆
* i 表示我是以哪个节点为堆顶根节点来构造的
*/
private void maxHeap(int[] a, int length, int i) {
if (a == null || a.length <= 1) {
return;
}
//左子节点
int left = i * 2 + 1;
//右子节点
int right =i * 2 + 2;
//设置最大值下标
//暂时设为i
int largest = i;
//left < length要放在a[left] > a[i] 前面
//不然会报溢出异常
if (left < length && a[left] > a[i] ) {
largest = left;
}
if ( right <length && a[right] > a[largest] ) {
largest = right;
}
//如果最大值的位置受到了变更
if (largest != i) {
//交换两者数据
exchangeElements(a,largest,i);
//再次子树构造大堆
//主要是为了倒数第二排以上的根节点
maxHeap(a, length, largest);
}
}
private void exchangeElements(int[] a, int i, int j) {
// TODO 自动生成的方法存根
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void main(String[] args) {
int [] a = {3,4,6,1,2,10,19,87,45,26,47,15,99};
HeapSort heapSort = new HeapSort();
heapSort.heapSort(a);
System.out.println(Arrays.toString(a));
}
}