要进行堆排序,首先需要将无序序列进行建堆,这里是建的大堆
网上的有些帖子,按照他们给出的堆排序代码和序列,确实能够输出对的排序,但要是输入自己的无序序列或者直接在他们的序列后面添加几个乱序,就出错了。
就自己动手实现了一下,代码如下,给出了每一步的解释和说明:
//堆排序
public class HeapSort{
//对一个节点进行建堆
public static void FilterHeap(int[] heap,int root,int n) {
int r = root;
//堆排序索引是从0开始的,所以一个根节点的左孩子节点的索引为child=2*root + 1
//如果从1开始排序,那么child=2*root
int child = 2*r+1;
int upper = n;
int temp;
while (child < upper) {
// 如果该节点有右孩子节点,如果有,比较左右两个孩子节点的关键字的大小,大的索引赋给左
// 赋给左的原因是方便根节点与其孩子节点比较大小,固定的和左孩子节点比较大小,同时有左孩子节点不一定有右孩子节点
if(child + 1 < upper && heap[child] < heap[child+1]) {
child = child + 1;
}
// 如果该节点小于其左孩子节点的关键字,就发生值的交换
if(heap[r] < heap[child]) {
temp = heap[r];
heap[r] = heap[child];
heap[child] = temp;
//同时,交换下来的孩子节点不一定满足大于其自己孩子节点的关键字,所以进行如上循环
r = child;
child = 2*r + 1;
}
//如果满足根节点大于其自己的孩子节点,就退出循环,因为建堆是自下而上的,也就是说下边的子节点都是排好序的
else break;
}
}
//对最后一个非叶子结点开始进行逆向建堆
//叶子节点没有孩子节点,无需建堆
//因为堆排序是从索引0开始的,其最后一个非叶子节点的取值为i=heap.length/2 - 1,不同于二叉堆从1开始
public static void heapBuilder(int[] heap,int n) {
for(int i = n/2 - 1; i >= 0; i--) {
FilterHeap(heap, i, n);
}
}
public static void heapSort(int[] heap,int n) {
heapBuilder(heap, n);
//显示第一次建堆完成的序列
System.out.println("第一次建堆:");
for (int i = 0; i < heap.length; i++) {
System.out.print(heap[i] +" ");
}
System.out.println();
int temp;
//每次将大堆的第一个元素与其最后一个元素值进行交换,同时堆的长度-1,所以其长度是个可变数
for (int i = n-1; i > 0; i--) {
temp = heap[0];
heap[0] = heap[i];
heap[i] =temp;
FilterHeap(heap, 0, i);
}
//显示堆排序完成的序列
System.out.println("堆排序完成:");
for (int i = 0; i < heap.length; i++) {
System.out.print(heap[i] +" ");
}
}
public static void main(String[] args) {
int[] heap = {1,2,63,5,765,94,3,84,6,55,8888};
int n = heap.length;
heapSort(heap, n);
}
}
输出结果为: