堆排序
堆的概念:
堆:本质是一种数组对象。特别重要的一点性质:任意的叶子节点小于(或大于)它所有的父节点。对此,又分为大顶堆和小顶堆,大顶堆要求节点的元素都要大于其孩子,小顶堆要求节点元素都小于其左右孩子,两者对左右孩子的大小关系不做任何要求。利用堆排序,就是基于大顶堆或者小顶堆的一种排序方法。下面,我们通过大顶堆来实现。
堆排序:
堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。
(1)用大根堆排序的基本思想:
① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新
的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次
同样要将R[1..n-2]调整为堆。
图解:
堆排序的时间复杂度是O(nLog2n) ,空间复杂度是O(1)。由于在构建堆得时候使得相同大小的元素可能出现顺序颠倒的情况,所以堆排序也是一个不稳定的排序方法。
算法代码实现 :
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int []data = new int[8];
for(int i= 0;i<data.length ;i++){
data[i] = sc.nextInt();
}
//堆排序
Main main = new Main();
data = main.heapSort(data);
for(int i = 0;i<data.length ;i++){
System.out.print(data[i]+" ");
}
}
/*堆排序建队算法*/
public int[] filterHeap(int data[],int root,int upper){
/*heap为待筛选的堆,root为堆的根结点,upper为无序区的上界*/
int child; //指向孩子结点
int item; //作为过渡变量
int r=root; //r指向根结点
child=2*root+1; //初始时为根结点的左孩子
while(child<upper){
/*比较左右孩子的关键字值,并取大者*/
if(child+1<upper && data[child+1]> data[child]){
child=child+1;
}
/*若根结点不满足堆的条件,则与孩子交换*/
if(data[r]<data[child]){
item=data[r];
data[r]=data[child];
data[child]=item;
r=child;
child=2*child+1; //使child>=upper,满足退出的条件
}else break; //若根满足堆的条件,则不交换,并退出筛选
}
return data;
}
public int[] heapSort(int[] data){
/*heap为待排序序列,n为序列长度*/
int i;
int item;//过渡变量
int n = data.length;
for(i=(n-1)/2;i>=0;i--){ //从第一个非叶子结点开始创建初始堆
filterHeap(data,i,n);
}
for(i=n-1;i>0;i--){ //做n-1趟排序,每次堆的大小减1
/*将堆顶元素与当前大根堆的最后一个元素交换*/
item=data[0];
data[0]=data[i];
data[i]=item;
/*筛选,将0~i的元素重新调整*/
filterHeap(data,0,i);
}
return data;
}
}