对HeapSort原理的分析和堆排序算法的简单实现

堆排序(HeapSort)是一种应用于海量数据处理的一种常用算法,它的时间复杂度为O(nlogn),其平均时间复杂度接近与其最坏的复杂度,所以堆排序对处理大数量的数据很有优势。-----[url=http://www.qinaide520.com]中国大姨夫[/url]()



堆排序定义

  n个关键字序列Kl,K2,…,Kn称为(Heap),当且仅当该序列满足如下性质(简称为堆性质):

  (1)ki=号。//k(i)相当于二叉树的非叶结点,K(2i)则是左孩子,k(2i+1)是右孩子。

换句话说: 若将此序列所存储的向量R[1..n]看做是一棵[b]完全二叉树[/b]的存储结构,则堆实质上是满足如下性质的完全二叉树:

  [b][i]树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。[/i][/b]


下面请看我的一个实现堆排序的具体例子:

问题:从一个具有3000万个int类型的数据堆中找出十个最大数据输出。(如果你的内存够大的话还可以处理更大的数据量)

这明显是一个处理海量数据的例子,我们可以这样来实现:假如这3000万个int类型数据存于一个数组中

[code="java"]private static int[] heap =new int[30000000];
static{
Random ran = new Random();
for(int i=0;i(1)用大根堆排序的基本思想

  ① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区

  ② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key

  ③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。

  ……

  直到无序区只有一个元素为止。

  (2)大根堆排序算法的基本操作:

  ① 初始化操作:将R[1..n]构造为初始堆;

  ② 每一趟排序的基本操作:将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆(亦称重建堆)。

这样的的话把每次BuildHeap(建立堆)所得到的无序堆的第一个元素R[1]存到另外一个数组就行了,因为通过BuildHeap()方法使堆顶即数组的第一个元素Heap[0]就是当前无序堆中最大的数。由于我们这里只要找出前十个最大数,所以BuildHeap()十次就行了。


下面是具体的代码*:

[code="java"]package SearchTop;

import java.util.Random;

/**
* 堆排序 实现类
* @author Administrator
*
*/
public class HeapSort {
private static int[] array ;
private static int[] heap =new int[30000000];
static{
Random ran = new Random();
for(int i=0;i=0;i--){
buildHeap(i,heap.length,heap);
}
}
/**
* 调整堆
* @param location 起始位置
* @param unSortLength 无序堆的长度
*/
public void buildHeap(int location,int unSortLength,int[] arr){
int temp;
int tempLoc;
//判断该父节点是否有左右孩子
if((tempLoc = (location+1)*2)arr[tempLoc-1]){//如果右节点大于左节点
if(arr[tempLoc]>arr[location]){//如果右节点大于父节点 就双方交换值
temp = arr[location];
arr[location] = arr[tempLoc];
arr[tempLoc] = temp;
buildHeap(tempLoc,unSortLength,arr);//递归
}
}else{//如果左节点大于右节点
if(arr[tempLoc-1]>arr[location]){//如果左节点大于父节点
temp = arr[location];
arr[location] = arr[tempLoc-1];
arr[tempLoc-1] = temp;
buildHeap(tempLoc-1,unSortLength,arr);//递归
}
}
}else if((tempLoc =((location+1)*2-1))arr[location]){//如果右节点大于父节点
temp = arr[location];
arr[location] = arr[tempLoc];
arr[tempLoc] = temp;
buildHeap(tempLoc,unSortLength,arr);//递归
}
}
}
}

[/code]

通过测试可以得到其中一组结果:

999999978
999999938
999999928
999999922
999999893
999999859
999999841
999999831
999999810
999999796
一共用时:1166毫秒


下面我再给出用常规的Exhaustive Sort实现一下:

[code="java"]package SearchTop;

import java.util.Random;
/**
* 通过优先队列中的穷举法去查找前十个最大数
* @author Administrator
*
*/
public class SortTop10 {
private static int[] array = new int[30000000];
static{
Random ran = new Random();
for(int i=0;iqueue[i]){
insert(i,value);
break;
}
}
}
/**
* 定义插入元素的方法
*/
public void insert(int index,int value){

for(int i=index;i
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值