比较排序算法
我们平时接触到的一些重要的排序算法,插入排序、归并排序、堆排序及快速排序都属于比较排序算法(即都是通过对元素进行比较操作来确定输入数组的次序)。已经证明了任意比较排序算法排序
n
个元素的最坏情况运行时间的下界为
堆排序
(二叉)堆是一个数组,它可以被看成一个近似的完全二叉树。除了最底层,该树是完全充满的,而且是从左向右充满。
堆的根结点是
A[1]
,给定一个结点
i
,他的父结点为
但是由于Java中数组的下标是从
0
开始直到
一个堆中结点的高度定义为该结点到叶结点最长简单路径上边的个数。
二叉堆可以分成两种形式:最大堆和最小堆。
最大堆
最大堆的性质就是除了根结点以外,其他结点满足
最小堆
相应的最小堆与最大堆类似,除了根结点以外,其他结点满足
A[PARENT(i)]<=A[i]
,也就是说某个结点的值大于等于其父结点的值。
在堆排序中,我们使用的是最大堆。最小堆通常用在构造优先队列中。
在介绍堆排序算法之前需要了解两个重要的堆的运算,分别是维护堆的性质和建堆。
维护堆的性质(很重要)
维护堆的性质这个操作,核心思想就是,针对一个结点
i
,假设其左右孩子结点为根节点的子树是最大堆,此时
伪代码如下:
MAX-HEAPIFY(A,i)
l=LEFT(i)
r=RIGHT(i)
if l<=A.heap-size and A[l]>A[i]
largest=l
else
largest=i
if r<=A.heap-size and A[r]>A[i]
largest=r
else
largest=i
if largest ≠i
exchange A[i] with A[largest]
MAX-HEAPIFY(A,largest)
建堆
建堆即是将一个数组
A[1,...,n]
转换最大堆的过程。
我们首先可以知道,对于数组
A[1,...,n]
中的元素
A(⌊n2⌋+1,...,n)
均为叶子结点(只需要考虑第
n
个元素一定为叶结点,则其父结点
伪代码如下:
BUILD-MAX-HEAP(A)
A.heap-size=A.length
for i=(A.length/2)下取整 downto 1
MAX-HEAPIFY(A,i)
堆排序算法
堆排序算法的思想很简单,首先是调用建堆的过程将一个数组
A[1,...,n]
建成最大堆,此时数组中的最大元素位于最大堆的根结点
A[1]
处,因此交换
A[1]
与
A[n]
,讲最大元素放在
A[n]
的位置。这时,
A[n]
已经处于正确的位置上,所以将这个结点
n
从最大堆中去掉(这一操作通过减少A.heap-size的值来实现),剩余的结点中,除了
伪代码如下
HEAPSORT(A)
BUILD-MAX-HEAP(A)
for i=A.length downto 2
exchange A[1] with A[i]
A.heap-size=A.heap-size-1;
MAX-HEAPIFY(A,1)
最后根据我们的分析过程给出整个利用最大堆实现堆排序的Java实现代码。
public class HeapSortTest {
public static void main(String[]args){
int[] A={ 9, 6, 3, 8, 5, 4, 7, 2, 1};
HeapSort(A);
for(int i=0;i<A.length;i++){
System.out.println(A[i]);
}
}
public static void swap(int[] A,int i,int j){
int temp =0;
temp=A[i];
A[i]=A[j];
A[j]=temp;
}
//排序方法
public static void HeapSort(int[] A){
if (A == null || A.length <= 1) {
return;
}
BuildMaxHeap(A);
for(int i=0;i<A.length;i++){
System.out.print(A[i]+",");
}
System.out.println();
int n=A.length;
System.out.println("数组长度:"+n);
for(int i=n-1;i>=1;i--){
swap(A,0,i);
MaxHeapify(A, 0,i);
}
}
//讲给的数组构建成一个最大堆
public static void BuildMaxHeap(int[] A){
if (A == null || A.length <= 1) {
return;
}
int n=A.length;
int index=(int)(n-1)/2;
for(int i=index;i>=0;i--){
MaxHeapify(A,i,n);
}
for(int i=0;i<A.length;i++){
System.out.print(A[i]+",");
}
System.out.println();
}
//维护最大堆的性质方法
public static void MaxHeapify(int[] A, int index,int heapSize){
int largest=index;
int left=index*2+1;
int right=index*2+2;
if(left<heapSize && A[left]>A[largest]){
largest=left;
}
if(right<heapSize && A[right]>A[largest]){
largest=right;
}
if(largest!=index){
swap(A,index,largest);
MaxHeapify(A,largest,heapSize);
}
}
}
最后运行了一下程序。