• Java实现---堆排序 Heap Sort


    堆排序快速排序归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法。学习堆排序前,先讲解下什么是数据结构中的二叉堆。

    堆的定义

      n个元素的序列{k1,k2,…,kn}当且仅当满足下列关系之一时,称之为堆。

      情形1:k<= k2i 且k<= k2i+1 最小化堆小顶堆

      情形2:k>= k2i 且k>= k2i+1 (化堆大顶堆

      其中i=1,2,…,n/2向下取整;

    若将和此序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。

      由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。

    堆的存储

      一般用数组来表示堆,若根结点存在序号0处, i结点的父结点下标就为(i-1)/2。i结点的左右子结点下标分别为2*i+1和2*i+2。

         

    堆排序的实现

      实现堆排序需要解决两个问题:

        1.如何由一个无序序列建成一个堆?

        2.如何在输出堆顶元素之后,调整剩余元素成为一个新的堆?

      先考虑第二个问题,一般在输出堆顶元素之后,视为将这个元素排除,然后用表中最后一个元素填补它的位置,自上向下进行调整:首先将堆顶元素和它的左右子树的根结点进行比较,把最小的元素交换到堆顶;然后顺着被破坏的路径一路调整下去,直至叶子结点,就得到新的堆。

      我们称这个自堆顶至叶子的调整过程为“筛选”。

      从无序序列建立堆的过程就是一个反复“筛选”的过程。

    示例代码:

    package heapSort;
    
    /**
     * 堆排序,采用顺序存储
     * 大根堆
     * @author 超超boy
     *
     */
    public class HeapSort2 {
    	int[] arr;
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		HeapSort2 heapSor = new HeapSort2();
    		int[] arr = {7,23,45,9,40,73,12,49};  //0下标放的是数组长度,
    	    heapSor.arr = arr;
    		heapSor.heapSort(arr);
    		
    		for(int i=0;i<arr.length;i++)
    			System.out.print(".."+arr[i]);
    	}
    	void heapAdjust(int[] arr,int s,int m){
    		//已知arr[s...m]中记录的关键字除arr[s]之外均满足堆的定义,本函数调整arr[s]的关键字,使arr[s...m]成为一个最大堆
    		int rc = arr[s]; //s是最后一个非叶子节点
    		
    		for(int j=2*s;j <= m;j = s*2){
    			if(j<m && arr[j]<arr[j+1])
    				j++;  //j为key较大的下标
    			if(rc >= arr[j]) break;
    		     arr[s] = arr[j];  //上移到父节点
    		     s=j;
    		}
    		arr[s]=rc;  //要放入的位置
    		
    	}
    	
    	void heapSort(int[] arr){
    		//对数组进行建堆操作,就是从最后一个非叶结点进行筛选的过程
    		for(int i=(arr.length-1)/2;i > 0;i--){//因为0没有使用,所以length-1
    			heapAdjust(arr,i,arr.length-1);  
    		}
    		System.out.println("........建堆完成.............");
    		
    		outputArr(1);
    		for(int i=arr.length-1; i>1; i--){
    			int temp = arr[1];
    			arr[1] = arr[i];
    			arr[i] = temp;
    			heapAdjust(arr,1,i-1);
    		}
    	}
    	void outputArr(int i){
    		
    		if(i <= arr[0]){
    			System.out.println(arr[i]);
    			outputArr(i*2);  //左
    			outputArr(i*2+1);  //右
    		}
    	}
    }
    

      运行结果:

    .....................
    73
    45
    40
    23
    49
    12
    9
    ..7..9..12..23..40..45..49..73

    堆排序分析

         堆排序方法对记录数较少的文件并不值得提倡,但对n较大的文件还是很有效的。因为其运行时间主要耗费在建初始堆和调整建新堆时进行的反复“筛选”上。

      堆排序在最坏的情况下,其时间复杂度也为O(nlogn)。相对于快速排序来说,这是堆排序的最大优点。此外,堆排序仅需一个记录大小的供交换用的辅助存储空间。

     转发请注明出处:http://www.cnblogs.com/jycboy/p/5689728.html

  • 相关阅读:
    iOS 8 UIAlertController 和 UIAlertAction
    iOS 利用异常 NSException 调试代码
    iOS 开发 atomic 与 nonatomic 区别
    iOS 9 HTTPS 的配置
    关于Frame加背景的那点事?
    java thread 线程锁同步,锁,通信
    java反射机制
    Java序列化与反序列化
    Java内存分配以及GC
    JavaBean入门笔记
  • 原文地址:https://www.cnblogs.com/jycboy/p/5689728.html
Copyright © 2020-2023  润新知