排序算法系列第四篇

7、堆排序

堆排序与简单选择排序的区别:

简单选择排序第一次进行n-1次的比较得到最小值,然后在剩余的n-1个记录中进行n-2次比较得出次小值。事实上,可以利用前n-1次比较的信息,来减少比较的次数,从而提高效率,堆排序采用树形结构保留了比较结果,从而减少了比较次数。

堆排序的基本思想:

1)先将数组data[0,1,...,n-1]建成一个大顶堆(或者小顶堆),即原始无序区;

2)取关键字最大(或最小)的记录,即堆顶元素,与无序区的最后一个记录交换,由此得到新的无序区data[1,2,...,n-2]和有序区data[n-1]

3)对新的无序区进行调整,重新调整成大顶(或者小顶)堆;

4)如此反复操作,直至排序结束。

堆排序的特点:

堆排序是一种树形选择排序,其特点是:将数组data[0,1,...,n-1]看成是一个完全二叉树,堆的含义表明,完全二叉树中所有非终端节点的值均不大于(或不小于)其左右孩子节点的值。若数组arr是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。

java实现:

public class SortAlgorithm {
	//堆排序
	public static void heapSort(int[] data){
        System.out.println("开始排序");
        int arrayLength = data.length;
        //循环建堆
        for(int i=0;i<arrayLength-1;i++){
            //建堆
            buildMaxHeap(data,arrayLength-1-i);
            //交换堆顶和最后一个元素
            swap(data,0,arrayLength-1-i);
            System.out.println(Arrays.toString(data));
        }
    }
    private static void swap(int[] data, int i, int j) {
        int tmp=data[i];
        data[i]=data[j];
        data[j]=tmp;
    }
    //对data数组从0到lastIndex建大顶堆
    private static void buildMaxHeap(int[] data, int lastIndex) {
        //从lastIndex处节点(最后一个节点)的父节点开始
        for(int i=(lastIndex-1)/2;i>=0;i--){
            //k保存正在判断的节点
            int k=i;
            //如果当前k节点的子节点存在
            while(k*2+1<=lastIndex){
                //k节点的左子节点的索引
                int biggerIndex=2*k+1;
                //如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在
                if(biggerIndex<lastIndex){
                    //若右子节点的值较大
                    if(data[biggerIndex]<data[biggerIndex+1]){
                        //biggerIndex总是记录较大子节点的索引
                        biggerIndex++;
                    }
                }
                //如果k节点的值小于其较大的子节点的值
                if(data[k]<data[biggerIndex]){
                    //交换他们
                    swap(data,k,biggerIndex);
                    //将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值
                    k=biggerIndex;
                }else{
                    break;
                }
            }
        }
    }
	public static void main(String[] args){
	  int[] a={49,38,65,97,76,13,27,49};  
	  System.out.println("排序之前:\n"+Arrays.toString(a));
	  heapSort(a);
	  System.out.println("排序之后:\n"+Arrays.toString(a));
	}

}

引自:http://www.cnblogs.com/sunnychuh/archive/2011/07/18/2109428.html

结果:

排序之前:
[49, 38, 65, 97, 76, 13, 27, 49]
开始排序
[38, 76, 65, 49, 49, 13, 27, 97]
[27, 49, 65, 38, 49, 13, 76, 97]
[13, 49, 27, 38, 49, 65, 76, 97]
[13, 49, 27, 38, 49, 65, 76, 97]
[13, 38, 27, 49, 49, 65, 76, 97]
[27, 13, 38, 49, 49, 65, 76, 97]
[13, 27, 38, 49, 49, 65, 76, 97]
排序之后:
[13, 27, 38, 49, 49, 65, 76, 97]

 

堆排序的性能:

堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成

堆排序的最坏时间复杂度O(nlogn)

堆序的平均性能较接近于最坏性能,相对于快速排序来说,这是堆排序最大的优点;

由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件,但对n较大的文件还是比较有效的;

堆排序是就地排序,辅助空间为O(1

它是不稳定的排序方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值