堆排序,也是一种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] (完全二叉树的性质)
代码
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);
}
}
}