堆排序(heap sort)

堆排序,也是一种O(NlogN)的算法。


算法简介

首先介绍下堆,什么是堆?

1.是一个完全(complete)二叉树;2,对于每一个子树而言,两个子节点的值都<=父节点(最大堆)或>=父节点(最小堆)。

满足上述两个条件的是树结构就称作是最大堆(最小堆)。

堆算法有一下几个操作:

buildMaxHeap:构造一个最大堆。

maxHeap:确保数据还是一个最大堆。

。。。

所以,算法简单的说就是:

1,构造一个最大堆,因为在一个最大堆中,其最大的数据一定存在根上。我们将这个最大的数移动到数组最后的位置,那么最大的数就已经在它的位置上了。

2,因为是一次交换动作,所以原来的树的结构还是保留在(即两个子树还是是一个最大堆),但是此时的根元素不是最大的元素了,所以我们需要refine剩下的数据,使其调整成一个最大堆。

3,调整后,此时的跟元素就是数据中第二大的数了,将其和倒数第二个数交换,那么第二大的数也找到它的位置了。

4,重复类似2,3的操作,知道树的结点个数为1。


这个算法只要理解到maxHeap就应该没问题了。

maxHeap的假设是调整的树种,其两个子树都是满足最大堆要求的。

于是maxHeap可以用一下伪代码表示出来,i表示根元素在数组中的索引,LEFT(i)表示获得i的左子树的根在数组中的索引,RIGH(i)表示获得i的右子树的根在数组中的索引

maxHeap(A,i)

l←LEFT(i)

r←RIGHT(i)

if l <= heapsize[A] and A[l] > A[i]

then largest ← l

else  largest ← i

if r <= heapsize[A] and A[r] > A[i]

largest ← r

 ## 需要因为交换操作,所以需要递归操作子树,确保子树满足最大堆性质

if(largest != i)   

then exchange A[i],A[largest]

maxHeap(A,largest)


那么我们怎么用上面的操作来个构造一个最大堆呢?上面提到maxHeap的假设是两个子树满足最大堆的要求。对于一个完全随机化的数据,我们怎么来构建一个最大堆呢?只有一个节点树,肯定是满足最大堆的要求的。所以,当我们可以从下往上构建一个最大堆。

BuildMaxHeap(A)

heapsize[A] ←length[A] ##假设数组是从1开始计数

for i ← [length[A] / 2] downto 1

maxHeap(A,i)


说明,一个数组中最后一个高度为2的子树的root的索引一定是[length[A] / 2] (完全二叉树的性质)


代码
说明,如果用C语言实现的话,那么LEFT(i),RIGHT(i)可以直接用位运算写成宏,这样效率提高很多。
java代码。
package sorting;

public class Data {
	
	/**
	 * generate an unsorted array of length n
	 * @param n length
	 * @param max the maximum integer element of this array
	 * @return an unsorted array consists of elements range from 1 to max
	 */
	public static int[] getArray(int n, int max){
		int[] result = new int[n];
		for(int i =0; i < n; i++){
			result[i] = (int)(Math.random() * max + 1);
		}
		return result;
	}
	/**
	 * print the array
	 * @param arg array
	 */
	public static void printArray(int[] arg){
		StringBuffer temp = new StringBuffer();
		for(int i = 0; i < arg.length; i++){
			temp.append(arg[i] + "\t");
		}
		System.out.println(temp);
	}
}

package sorting;

public class HeapSort {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HeapSort hs = new HeapSort();
		int[] data = Data.getArray(10, 50);
		System.out.print("Source data:\t");
		Data.printArray(data);
		hs.heapSort(data);
		System.out.print("Sorted data:\t");
		Data.printArray(data);

	}
	
	public void heapSort(int[] arg){
		buildMaxHeap(arg);
		int temp;
		for(int i = arg.length; i > 1; i--){
			temp = arg[i - 1];
			arg[i - 1] = arg[0];
			arg[0] = temp;
			maxHeap(arg,0,i -1);
		}
		
	}
	
	private void buildMaxHeap(int[] arg){
		for(int i = (arg.length / 2 - 1); i >= 0; i--){
			maxHeap(arg,i,arg.length);
		}
	}
	/**
	 * 
	 * @param arg
	 * @param index
	 * @param length the size of the tree. Since there may be some sorted elements in this array, so the tree's size is mutable
	 */
	private void maxHeap(int[] arg, int index,int length){
		int left = index * 2 + 1;
		int right = index * 2 + 2;
		int largest = index;
		if(left < length && arg[left] > arg[largest])
			largest = left;
		if(right < length && arg[right] > arg[largest])
			largest = right;
		if(largest != index){
			int temp = arg[index];
			arg[index] = arg[largest];
			arg[largest] = temp;
			maxHeap(arg,largest, length);
			
		}
	}

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值