堆排序
标签(空格分隔): 算法
堆实际上是一种满二叉树,所以我们可以直接利用父母节点与孩子节点之间在数组中的位置关系来操纵,而不需要真的建立一棵二叉树。
堆分为大顶堆(父节点比所有左右子孩子的排序码都要大)和小顶堆(父节点比所有左右子孩子的排序码都要小);
堆排序的过程分为2个部分:
- 根据输入的初始数据,建立初始堆;
- 通过一系列的元素交换和重新调整堆进行排序。
假设父节点在数组中的位置为(i),则它的左孩子的位置为(i*2+1),右孩子的位置为(i*2+2).
代码如下:
public class HeapSort {
/**
* 将最大的元素向下调整,生成大顶堆
* @param start
* @param end
* @param heap
*/
public static int[] siftDown(int start, int end, int[] heap) {
int i = start, j = i * 2 + 1;//令j指向左孩子
int temp = heap[i];
while(j <= end) {
if(j < end && heap[j] < heap[j+1])
j++; //令j指向较大的孩子
if(heap[i] >= heap[j])
break; //当前元素已是较大的元素
else {
heap[i] = heap[j];
i = j;
j = i * 2 + 1;
}
}
heap[i] = temp;
return heap;
}
/**
* 堆排序
* @param heap
*/
public static int[] heapSort(int[] heap) {
//建立初始堆,从第一个非叶节点开始调整
for(int i=(heap.length-2)/2; i>=0; i--) {
heap = siftDown(i, heap.length-1, heap);
}
//依次将大顶堆的对顶元素移动至最后,然后重新调整为大顶推
for(int i=heap.length-1; i>0; i--) {
int temp = heap[0];
heap[0] = heap[i];
heap[i] = temp;
heap = siftDown(0, i-1, heap);
}
return heap;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] nums = {5,3,7,1,10,4};
int[] res = heapSort(nums);
System.out.println(Arrays.toString(res));
}
}
算法复杂度为:O(nlogn).