堆排序算法

来源:互联网 发布:无忧保姆 知乎 编辑:程序博客网 时间:2024/06/11 01:12

       上一篇文章讲到了最大堆最小堆算法,今天又用最大堆写了个堆排序。正序使用最大堆,倒序使用最小堆。堆排序是简单选择排序算法的一种改进排序算法,时间复杂度为O(nlogn)。以正序为例,该算法的思想是利用数组构建最大堆,每次将最后一个结点与堆顶互换,这样最大的数就排到了数组的尾端。再用还未排好位置的其他结点重构最大堆,堆顶再与末结点互换。。。以此循环直到所有结点都排在正确的位置。

/** * 堆排序 * @author dwl * */public class HeapSort {private int[] data;public HeapSort(int[] data){this.data = data;//从最后一个拥有子结点的结点开始重构最大堆for(int i =data.length/2-1;i>=0;i--){buildHeap(i, data.length);}}/** * 构建大顶堆 * @param i 父结点位置 * @param last 可交换子节点位置 */private void buildHeap(int i,int last){int temp = 0;int left =left(i);int right = right(i);//左右孩子都参与可重构if(right<last){//获取左右孩子中较大数的下标temp = max(left, right);if(data[temp]>data[i]){//交换父子结点swap(i, temp);//交换结点后可能对原子结点的子树产生影响,重构该子结点的子数buildHeap(temp, last);}}else if(left<last){//只有左孩子可以参加重构//满足条件直接交换,无需重构if(data[left]>data[i])swap(i, left);}}/** * 根据父结点下标获取 * 左孩子下标 * @param i * @return */private int left(int i){return ((i+1)<<1)-1;}/** * 根据父结点下标获取 * 右孩子下标 * @param i * @return */private int right(int i){return (i+1)<<1;}/** * 交换两个结点 * @param i * @param j */private void swap(int i,int j){int temp = data[i];data[i] = data[j];data[j] = temp;}/** * 返回连个结点中较大的下标 * @param i * @param j * @return */private int max(int i,int j){if(data[i]>=data[j])return i;return j;}/** * 最后一个结点与根结点交换,重构该结点前的其他结点 * @param last */public void changeRootLast(int last){int temp = data[0];data[0] = data[last];data[last] = temp;//最后一次不再重构堆if(last>1){buildHeap(0, last-1);}}/** * 获取数组 * @return */public int[] getData(){return data;}/** * 获取排序后的数组 * @return */public int[] getSort(){    //循环将堆顶放入i的位置for(int i = data.length-1;i>0;i--){changeRootLast(i);}return data;}public static void main(String[] args) {int[] data = {5,23,4,1,83,3,6,34,7};HeapSort heap = new HeapSort(data);int[] result =heap.getData();//输出初始堆for(int n:result){System.out.print(n+";");}int[] sort = heap.getSort();System.out.println();//输出排好序的数组for(int n:sort){System.out.print(n+";");}}}

测试结果如下图: