堆排序及其Java实现

1.堆的定义:

一个完全二叉树中,任意父结点总是大于或等于(小于或等于)任何一个子节点,则为大根堆(小根堆)。

2.堆的存储:

完全二叉树适合采用顺序存储的方式,因此一个数组可以看成一个完全二叉树。用数组来表示堆,下标为 i 的结点的父结点下标为(i-1)/2;其左右子结点分别为 (2i + 1)、(2i + 2)。

编号特点:
从一个结点的编号就可推得其双亲,左、右孩子,兄弟等结点的编号。假设编号为i的结点是ki(1≤i≤n),则有:
    ①若i>1,则ki的双亲编号为i/2;若i=1,则Ki是根结点,无双亲。
    ②若2i≤n,则Ki的左孩子的编号是2i;否则,Ki无左孩子,即Ki必定是叶子。因此完全二叉树中编号i>n/2的结点必定是叶结点。
    ③若2i+1≤n,则Ki的右孩子的编号是2i+1;否则,Ki无右孩子。

注:ki(0≤i≤n)满足数组下标时,则可能的左右孩子分别为2i+1、2i+2。

3.堆排序

1)基本思想
利用大根堆(小根堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。

将待排序的序列构造成一个大根堆,此时序列的最大值为根结点依次将根结点与待排序序列的最后一个元素交换,再维护从根结点到该元素的前一个结点为大根堆,如此往复,最终得到一个递增序列。

2)实现逻辑

1、将初始待排序关键字序列(R0,R1,R2....Rn)构建成大根堆,此堆为初始的无序区;

2、将堆顶元素R[0]与最后一个元素R[n]交换,此时得到新的无序区(R0,R1,R2,......Rn-1)和新的有序区(Rn);

3、由于交换后新的堆顶R[0]可能违反堆的性质,因此需要对当前无序区(R0,R1,R2,......Rn-1)调整为新堆。

4、不断重复此2、3步骤直到有序区的元素个数为n-1,则整个排序过程完成。

3)算法分析


4)筛选算法(shift())

堆排序的关键是构造初始堆,这里采用筛选算法建堆:假设完全二叉树的某个结点i,它的左右子树均已经是堆,接下来需要将R[2i+1]与R[2i+2]之中的最大者与R[i]比较,若R[i]较大,则此完全二叉树即为大根堆退出循环;若R[i]较小,则将其与最大的孩子的元素交换,这有可能破坏下一级的堆,所以继续采用上述方法构造下一级的对,直至完全二叉树中结点i构成堆为止。

5)实现堆排序

在初始堆构造好后,根结点一定是最大关键字结点,将其放到序列的最后,即与最后一个叶子交换。后续根据2)实现逻辑实现即可。


堆排序的Java实现:

public class HeapSort {

	//shift()元素下沉法,假设除了根结点之外,根结点的左右子树均为堆
	public void shift(int[] a, int low, int high){//low为根结点元素,high为目前要处理的堆的最后一个元素
		int i = low;
		int j = 2 * i + 1;//a[j]为a[i]的左孩子
		int tmp = a[i];//tmp存放根结点
		while(j <= high){
			if(j < high && a[j] < a[j+1])
				j++;
			if(tmp < a[j]){//根结点元素小于其孩子结点元素
				a[i] = a[j];//a[j]上浮到当前根结点的位置
				i = j; //修改i和j的值,继续向下筛选
				j = 2 * i + 1;
				
			}
			else break;//此时根结点的元素值大于孩子结点,则整棵要处理的树均为堆,退出循环
		}
		a[i] = tmp; //被筛选结点(原始的根结点)下沉到合适的位置
	}
	
	//HeapSort
	public int[] heapSort(int[] a){
		int n = a.length-1;
		int tmp = 0;
		//循环调用shift()方法,构建初始堆
		for(int i = n /2; i >= 0; i --)//长度为n的数组构建的完全二叉树的根结点数目为n/2,因为要从下往上构建堆,所以从最后一个根结点开始
			shift(a, i, n);
		//根据大根堆的性质,根元素为值最大的元素,将其与最后一个元素对换,最大的元素归位
		//继续调用shift()方法,将剩余的i-1个元素重新构建成堆
		for (int i = n; i >= 0; i--){
			tmp = a[i];
			a[i] = a[0];
			a[0] =tmp;
			shift(a, 0, i - 1);
		}
		return a;
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] a = {6,8,7,9,0,1,3,2,4,5};
		HeapSort hs = new HeapSort();
		hs.heapSort(a);
		for(int i = 0; i<a.length;i++)
			System.out.print(a[i] + " ");

	}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值