堆排序算法
堆排序算法是基于选择排序思想的算法,其利用堆结构和二叉树的一些性质来完成数据的排序。
堆排序的关键是首先构造堆结构。堆结构是一种树结构,准确来说是一个完全二叉树。
在这个树中每个结点对应于原始数据的一个记录,并且每个结点应满足以下条件:(最小堆,最大堆)
1如果按照从小到大的顺序排序,要求非叶结点的数据要大于或等于其左,右子结点的数据。
2如果按照从大到小的顺序排序,要求非叶结点的数据要小于或等于其左,右子结点的数据。
过程
一个完整的堆排序需要经过反复的两个步骤:构造堆结构和堆排序输出。 筛运算进行结点数据的调整,直到所有结点最后满足堆结构的条件为止。
筛运算主要针对非叶结点进行调整。
二叉堆的定义
二叉堆是完全二叉树或者是近似完全二叉树。 二叉堆满足二个特性:
1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。 当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。
当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。
堆的存储
一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。
代码
public class HeapSort {
void swap(int[] data,int i,int j){//交换结点
if(i==j){
return;
}
int temp=data[i];
data[i]=data[j];
data[j]=temp;
}
void createMaxHeap(int[] data,int lastIndex){
//从 堆结构中最后一个结点lastIndex 开始重新构造堆结构
for(int node=(lastIndex-1)/2;node>=0;node--){//(lastIndex-1)/2为lastIndex的父结点下标
//保存当前正在判断的节点
int current=node;
//若当前结点的子结点存在
while(2*current+1<=lastIndex){
//biggerIndex总是记录较大结点的下标,先赋值为当前判断结点的左子结点
int biggerIndex=2*current+1;//左子结点
if(biggerIndex<lastIndex){
//若右子结点存在,否则此时biggerIndex应该等于lastIndex
if(data[biggerIndex]<data[biggerIndex+1]){
//若右子结点值比左子结点值大,则biggerIndex记录的是右子结点的下标值
biggerIndex++;//右子结点
}
}
if(data[current]<data[biggerIndex]){
//若当前结点值比子结点最大值小,则交换两者的值,交换后将biggerIndex值赋值给current
swap(data,current,biggerIndex);
current=biggerIndex;//重新调整 子树的堆结构
}else{
break;
}
}
}
}
void toHeadpSort(int[] data){
for(int i=0;i<data.length-1;i++){
createMaxHeap(data,data.length-1-i);//构造堆结构
swap(data,0,data.length-1-i);//堆排序输出
}
}
}