Java学习手册:(数据结构与算法-排序)堆排序

本文深入解析了堆的概念,包括小根堆和大根堆的特点,详细阐述了如何通过筛选法构建和调整堆,以及如何利用堆进行高效排序。通过具体代码示例,展示了堆排序的实现过程。

一、什么是堆?

堆是一种数据结构,可以把堆看成一棵完全二叉树,这棵完全二叉树满足:任何一个非叶结点的值都不大于(或不小于)其左右孩子结点的值。

堆分为小根堆和大根堆。对于一个小(大)根堆,它是具有如下特征的一棵完全二叉树:

1、若树根结点存在左孩子,则根结点的值小(大)于等于左孩子结点的值。

2、若树根结点存在右孩子,则根结点的值小(大)于等于右孩子结点的值。

3、以左、右孩子为根的子树又各是一个堆。

堆排序的过程主要需要解决两个问题:

①按堆定义建初堆;

②去掉最大值之后重建堆,得到次大值;

二、当堆顶元素改变时,如何重建堆?

1、首先将完全二叉树根结点中的记录移出,该记录为待调整记录,此时根结点相当于空结点。

2、从空结点的左右子树中选出一个关键字较小的记录,如果该记录的关键字小于待调整记录的关键字,则将该记录上移至空结点中。

3、此时,原来那个关键字较小的子结点相当于空结点。

4、重复上述移动过程,直到空结点左、右的关键字均不小于待调整记录的关键字,此时将待调整记录放入空结点即可。

5、上述调整方法相当于把待调整记录逐步向下“筛”的过程,所以一般称为“筛选法”。

三、如何由一个任意序列建初堆?

一个任意序列看成是对于的完全二叉树,由于叶子结点可以视为单元素的堆,因而可以反复利用“筛选法”,自底向上逐层把所有以非叶结点为根的子树调整为堆,直到将整个二叉树调整为堆。可以证明,最后一个非叶子结点位于n/2(向下取整)个元素,n为二叉树结点数目。因此,“筛选法”从第n/2(向下取整)个元素开始,逐层向上倒退,直到根结点。

四、如何利用堆进行排序?

1、将待排序记录按照堆的定义建初堆,并输出堆顶元素;

2、调整剩余的记录序列,利用“筛选法”将前n-i个元素重新筛选并建立一个新堆,再输出堆顶元素;

3、重复执行2进行n-1次筛选;

算法思想:

①构建堆;

②交换堆顶元素与最后一个元素位置;

package com.haobi;
/*
 * 堆排序(小根堆)
 */
public class HeapSort {
	//调整小根堆
	public static void adjustMinHeap(int[] array, int pos, int len) {//pos-起始位置;len-长度;
		int parent;
		int child;
		for(parent=array[pos];2*pos+1<=len;pos = child) {//!!!for循环最后一步: pos=child -> 将更新后的child位置赋值给pos 
			child = 2*pos+1;//左孩子结点位置
			if(child<len && array[child]>array[child+1]) {//如果左孩子大于右孩子
				child++;//自增,判断右孩子与父结点的大小
			}
			if(array[child]<parent) {//如果右孩子小于父结点
				array[pos] = array[child];//将右孩子结点的值赋给父节点,也就是该循环的起始结点
			}else {
				break;
			}
		}
		array[pos] = parent;//!!!将parent值赋给array[pos],如果有更改则array[pos]表示叶子结点
		
	}
	public static void MinHeapSort(int[] array) {
		int i;
		int len = array.length;
		for(i=len/2-1;i>=0;i--) {//从最后一个非叶子结点(位于n/2(向下取整)个元素)开始,向前调整
			adjustMinHeap(array,i,len-1);
		}
		for(i=len-1;i>=0;i--) {//调整(len-1)次
			int temp = array[0];//将堆的第一个元素(堆顶)取出存入temp
			array[0] = array[i];//将最后一个元素取出放入堆顶
			array[i] = temp;//将堆首元素放在数组的最后一个元素所在的位置
			adjustMinHeap(array,0,i-1);//递归(len-1)次
		}
		
	}
	public static void main(String[] args) {
		int[] array = {4,1,3,2,16,9,10,14,8,7};
		MinHeapSort(array);
		for(int i=0;i<array.length;i++) {
			//小根堆逆序输出的原因是:将最小的元素始终与未定序数组的最后一个元素交换,所以数组中存放的是逆序
			System.out.print(array[i]+" ");
		}
	}
}

程序输出结果如下:

16 14 10 9 8 7 4 3 2 1 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值