堆排序原理及JAVA实现

标签: 堆排序 选择类排序 算法 Java
26人阅读 评论(0) 收藏 举报
分类:

选择类排序

  • 基本思想:在第i趟的记录序列中选取关键字第i小的记录作为有序序列的第i个记录。
  • 关键:如何从剩余的待排序列中找出最大或最小的那个记录。

堆排序是利用堆的性质对记录序列进行排序的一种排序方法。堆排序是选择类排序

堆的定义

堆是满足下列性质的数列{K0,K1,K2,……,K(n-1)}:

  • (1)小根堆:Ki <= K(2i+1),且Ki <= K(2i+2)(0<=i<=n/2-1);
  • 或者(2)大根堆:Ki >= K(2i+1),且Ki >= K(2i+2)(0<=i<=n/2-1);

其中,Ki相当于二叉树的非叶子节点,K(2i+1)是左孩子节点,K(2i+2)是右孩子节点。

若将此数列看成是一颗完全二叉树,则堆是空数列或是满足下列特性的完全二叉树:

  1. 其左、右子树分别是堆;
  2. 当左、右子树不空时,根结点的值小于(或大于)左、右子树根结点的值。



堆(大根堆)排序基本思想及步骤

基本思想:

  1. 建堆:先将待排序序列文件R[0……n-1]构建成一个大根堆,此堆为初始的无序区;
  2. 交换:将堆顶记录(无序区的最大记录R[0])和无序区的最后一个记录R[n-1]交换,无序区记录个数减去1,有序区记录个数加1,由此得到新的无序区R[0……n-2]和有序区R[n-1];
  3. 调整:将当前无序区R[0……n-2]调整为大根堆;
  4. 重复交换操作:将堆顶记录和无序区最后一个记录交换,无序区记录个数减去1,有序区记录个数加1;
  5. 重复调整操作:将当前无序区调整为大根堆;
  6. ……
  7. 直到无序区只有一个元素为止。

假设待排序序列为{7, 3, 5, 1, 6},要将其按升序排序,其堆排序具体过程如下:

步骤一:建初始堆。(升序使用大根堆,降序使用小根堆)

初始的无序序列逻辑及物理存储结构如下:


从最后一个非叶子结点开始,其下标为i = arr.length/2-1 = 1,即从arr[1]处开始,看其左、右孩子结点的值,找出左、右孩子结点中值最大的结点,记住其下标,然后与其父结点交换;然后,从左往右,从下向上,依次进行调整。直到将其调整成大根堆。


步骤二:交换。将堆顶记录和无序区最后一个记录交换。


圈出来的部分就是新的无序区,即需要下次调整为大根堆的部分。此时下标为4的arr[4]就是有序区。

步骤三:调整。将新的无序区调整为大根堆。

从最后一个非叶子结点(新的无序区的最后一个非叶子结点)开始,其下标为i = (arr.length-1)/2-1 = 1,即从arr[1]处开始,看其左、右孩子结点的值,找出左、右孩子结点中值最大的结点,记住其下标,然后与其父结点交换;然后,从左往右,从下向上,依次进行调整。直到将其调整成大根堆。

步骤四:然后重复交换、调整、交换、调整……操作,直到无序区只有一个记录。


圈出来的是新的无序区,是下一次需要调整的新的无序区。

最终的堆排序结果为下图:


此时,堆排序结束。

代码实现:

public class HeapSort {
	
	/**
	 * 调整一个非叶子结点及它的左、右孩子这三个结点为一个大根堆
	 * @param arr
	 * @param i
	 * @param length
	 */
	private static void adjust(int[] arr, int i, int length) {
		//先保存第一个非叶子结点记录
		int temp = arr[i];
		//从左孩子结点开始
		for(int j = 2*i+1; j < length; j = 2*j+1) {
			//有右孩子,且左孩子记录小于右孩子记录
			if(j+1 < length && arr[j] < arr[j+1]) {
				//用j来保存孩子结点中比较大的孩子结点的下标
				j++;
			}
			//用孩子结点中比较大的孩子的记录和父结点记录做比较
			if(temp < arr[j]) {
				//父结点记录保存最大记录
				arr[i] = arr[j];
				//记录孩子结点的下标,要把父结点的记录赋值给该孩子记录
				i = j;
			} else {
				break;
			}
		}
		arr[i] = temp;
	}
	
	private static void swap(int[] arr, int i, int j) {
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	
	/**
	 * 大根堆排序
	 * @param arr
	 */
	public static void heapSort(int[] arr) {
		if(null == arr) {
			return;
		}
		/**
		 * 构建大根堆
		 */
		for(int i = arr.length/2-1; i >= 0; i--) {
			adjust(arr, i, arr.length);
		}
		/**
		 * 交换 + 调整
		 */
		for(int i = arr.length-1; i >= 0; i--) {
			//先交换堆顶记录和无序区最后一个记录
			swap(arr, 0, i);
			//调整无序区为大根堆
			adjust(arr, 0, i);
		}
	}
	
	private static void showArr(int[] arr) {
		for(int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
	}
	
	public static void main(String[] args) {
		int[] arr = {7, 3, 5, 1, 6};
		/**
		 * 堆排序
		 */
		heapSort(arr);
		showArr(arr);
	}

}

运行结果:


效率:

时间复杂度:O(nlogn);

空间复杂度:O(1);

稳定性:不稳定排序。

查看评论

【排序算法】堆排序原理及Java实现

1、基本思想堆是一种特殊的树形数据结构,其每个节点都有一个值,通常提到的堆都是指一颗完全二叉树,根结点的值小于(或大于)两个子节点的值,同时,根节点的两个子树也分别是一个堆。 堆排序就是利用堆(...
  • jianyuerensheng
  • jianyuerensheng
  • 2016-04-27 18:34:23
  • 12799

堆排序(Heapsort)之Java实现

堆排序算法介绍 堆是一种重要的数据结构,为一棵完全二叉树, 底层如果用数组存储数据的话,假设某个元素为序号为i(Java数组从0开始,i为0到n-1), 如果它有左子树,那么左子树的位置是2i+1,如...
  • kimylrong
  • kimylrong
  • 2013-12-05 22:25:31
  • 54664

算法(第四版)学习笔记之java实现堆排序

继上一篇实现基于堆的优先队列后,这次将利用上一次完成的基于堆的能够重复删除最大元素操作的优先队列来实现一种经典而优雅的排序算法,称之为堆排序。 堆排序可分为两个阶段: 1.构建堆:在堆的构建过程中...
  • l243225530
  • l243225530
  • 2015-07-26 16:02:37
  • 1227

HeapSort堆排序Java实现图文代码详解

堆排序(Heapsort)堆积树设计的一种排序算法,可以利用数组的特点快速定位指定索引的元素。 排序图如下:(gif来自维基百科) 堆排序的过程就是首先构建大根堆,然后对顶元素(及最大元素)与最...
  • wg1033755123
  • wg1033755123
  • 2015-04-12 14:04:13
  • 1041

算法分析(一)堆排序原理及java实现

一、堆排序思想 以下以大根堆为例: 1、先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区 2、 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新...
  • liuhaiabc
  • liuhaiabc
  • 2016-09-29 19:29:27
  • 312

java递归实现堆排序

堆排序实际上是把数组当成一个完全二叉树来处理。完全二叉树定义:只有最后一行或倒数第二行才有叶结点,并且最后一行的叶结点都在最左边。从右到左,从下往上找非叶节点(第一个是arr.length/2-1,因...
  • qq_37491039
  • qq_37491039
  • 2018-03-24 15:56:43
  • 13

堆排序算法原理及JAVA实现

基本思想:堆排序是一种树形选择排序,是对直接选择排序的有效改进。 实例图: 初始序列:46,79,56,38,40,84 建堆: 交换,从堆中踢出最大数 ...
  • xuxurui007
  • xuxurui007
  • 2012-06-11 00:18:17
  • 3949

堆排序原理(java实现)

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。(摘自百度百科)      想知道什么是堆排序,就得先...
  • qq_39776901
  • qq_39776901
  • 2017-08-18 21:41:35
  • 156

【java面试】算法篇之堆排序

一、堆的概念 堆是一棵顺序存储的完全二叉树。完全二叉树中所有非终端节点的值均不大于(或不小于)其左、右孩子节点的值。 其中每个节点的值小于等于其左、右孩子的值,这样的堆称为小根堆; 其中每个节点的值大...
  • qq_21492635
  • qq_21492635
  • 2017-06-12 14:23:38
  • 3122

堆排序原理及其实现(C++)

堆排序原理及其实现(C++)1 堆排序的引入 我们知道`简单选择排序`的时间复杂度为O(n^2),熟悉各种排序算法的朋友都知道,这个时间复杂度是很大的,所以怎样减小简单选择排序的时间复杂度呢?从上...
  • yanglr2010
  • yanglr2010
  • 2016-10-18 21:48:02
  • 5372
    个人资料
    等级:
    访问量: 187
    积分: 163
    排名: 104万+
    文章存档