您的位置:首页 > 其它

学习堆排序

2016-11-24 12:03 183 查看
  首先,看一下堆的定义;

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

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

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

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

该排序的思想是;首先建立二叉堆,这个阶段花费O(N)时间,然后我们执行N次deleteMin操作。按照顺序,最小的元素先离开堆,通过将这些元素记录到第二数组,最后在将数组拷贝回来,得到N个元素的顺序,由于每个deleteMIn花费时间O(logN), 因此,总的运行时间是O(NlogN). 优先队列,可以用于O(NlogN)时间排序, 基于该思想的算法叫做堆排序。

该算法的主要问题是使用一个附加的数组,一次存储需求增加一倍,为了回避使用第二个数组的,可以在每次deleteMin之后,堆缩减1,因此,位于堆中左后的单元,可以存储刚刚存放删除的元素。使用这种策略,该数组将以递减的的顺序包含这些元素.

java代码的例子:

public class HeapSort {

public static void main(String[] args) throws Exception{
Integer [] a  = new Integer[]{32,12,345,5,66,23};
heapSort(a);

Arrays.stream(a).forEach(System.out::println);
}

/**
* Internal method for heapSort that is used in  deleteMax and buiildHeap
* @param i the position from which to percolate down
* @param n the binary size of the binary heap
*/
public static void percDown(Integer[] a,int i, int n){
int child;
int temp;

for(temp= a[i]; leftChild(i) < n; i = child){
child = leftChild(i);

if(child != n-1  && a[child] < a[child+1])
child++;

if(temp < a[child])
a[i] = a[child];
else
break;
}
a[i] = temp;
}

private static int leftChild(int i){
return 2 * i + 1;
}

public static void heapSort(Integer[] a){

/**初始化堆的时候是对所有的非叶子结点进行筛选。
最后一个非终端元素的下标是[n/2]向下取整,所以筛选只需要从第[n/2]向下取整个元素开始,从后往前进行调整。
*/
for(int i = a.length/2-1; i>=0; i--){ //buildHeap
percDown(a,i,a.length);
}

for(int i=a.length-1; i > 0; i--){
swapReferences(a,0,i);  //deleteMax
percDown(a,0,i);
}
}

//deleteMax
public static void swapReferences(Integer[] a, int i, int n){
Integer temp=a[i];
a[i] = a
;
a
= temp;
}

}


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

  堆排序在最坏的情况下,其时间复杂度也为O(nlogn)。相对于快速排序来说,这是堆排序的最大优点。

   

 

  

    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: