排序算法八:堆排序

堆排序

堆排序(Heap Sort),顾名思义,借助于堆的形式来实现排序。这个堆分为大根堆和小根堆两种,大根堆用来实现从小到大的顺序排序,小根堆则用来实现从大到小的降序排序。每构造出一个大(小)根堆,即获得了一个最优值(根节点),将该根节点去掉,剩余的继续进行构造堆的做法,获得剩余元素的最优值,重复之前的做法,直到全部完成排序为止。
堆排序的难点即在于堆的构成和实现。以大根堆为例,先将一个无序队列看做一个堆。其中,坐标 0 元素为根元素,1、2坐标元素为 0 元素的子元素,3、4坐标元素为 1 元素的子元素,5、6坐标元素为 2 坐标的子元素,以此类推。然后,从根堆的最底端子节点(非叶子节点),也即中间节点开始分别与其子节点进行比较,将其中的大者作为该子节点的元素。逐个排查所有的非叶子节点,直到根节点为止,将最大元素赋给根节点。这样经过排查,即找到了堆的最大值。将该最大值与堆的末端节点对换,重复上述过程,对剩余的元素重新进行堆的构造和最优值的对换,直到全部排序完成为止。
Java代码如下:
	/**
	 * 大根堆排序:实现顺序排序
	 * @param data
	 * @param i
	 */
	private static void heapSort(int[] data, int length) {
		//递归结束
		if (1 == length) {
			return;
		}
		//获取最底端的非叶子节点的坐标
		int mid = (length -1)>>1;
		//构造堆
		//左右子节点的坐标
		int left = 0;
		int right = 0;
		for (int i = mid; i >= 0; i--) {
			//与左孩子节点比较
			left = (i+1)<<1;
			if (left<=length && data[i]<data[left]) {
				swap(data,i,left);
			}
			//与右孩子节点比较
			right = left -1;
			if (right<=length && data[i]<data[right]) {
				swap(data,i,right);
			}
		}
		//将最大值与队列最后一个元素对换
		swap(data, 0, length);
		
		//递归上面的过程
		heapSort(data, length - 1);
		
	}

	/**
	 * 数组内 i 坐标元素与 j 坐标元素互换
	 * @param data
	 * @param i
	 * @param j
	 */
	private static void swap(int[] data, int i, int j) {
		int temp = data[i];
		data[i] = data[j];
		data[j] = temp;	
	}	

该算法的初始参数为数据data和数据末点坐标 data.length-1。因为只有最底端的非叶子节点的叶子节点有可能出现越界情况,因此,这里可以做一点改进,减少不必要的越界判断。
代码如下:
	/**
	 * 大根堆排序:实现顺序排序
	 * @param data
	 * @param i
	 */
	private static void heapSort2(int[] data, int length) {
		//递归结束
		if (1 == length) {
			return;
		}
		//获取最底端的非叶子节点的坐标
		int mid = (length -1)>>1;
		//构造堆
		//左右子节点的坐标
		int left = 0;
		int right = 0;
		//最底端的非叶子节点比较
		int i = mid;
		left = (i+1)<<1;
		if (left<=length && data[i]<data[left]) {
			swap(data,i,left);
		}
		right = left -1;
		if (right<=length && data[i]<data[right]) {
			swap(data,i,right);
		}
		i--;
		//剩余非叶子节点比较
		for (; i >= 0; i--) {
			//与左孩子节点比较
			left = (i+1)<<1;
			if (data[i]<data[left]) {
				swap(data,i,left);
			}
			//与右孩子节点比较
			right = left -1;
			if (data[i]<data[right]) {
				swap(data,i,right);
			}
		}
		//将最大值与队列最后一个元素对换
		swap(data, 0, length);
		
		//递归上面的过程
		heapSort(data, length - 1);
		
	}
	
	/**
	 * 数组内 i 坐标元素与 j 坐标元素互换
	 * @param data
	 * @param i
	 * @param j
	 */
	private static void swap(int[] data, int i, int j) {
		int temp = data[i];
		data[i] = data[j];
		data[j] = temp;	
	}	

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值