堆排序
堆排序使用二叉树的一些思想以及结论,但并没有真正的建立树。一切的操作都是在操作数组
有些专用的词可能使用不对,但算法思想和代码实现绝对没有问题
-
关于完全二叉树
一个一维数组对应一个完全二叉树,在不越界并且子节点,父节点都存在时,一个结点(索引为 index)的父节点在数组中对应的索引为(index-1)/2,左子节点2index+1,右子节点2index+2。数组从0开始存储。
-
大顶堆与小顶堆
在一个二叉树中,所有的父节点都大于两个子节点,这就是大顶堆
在一个二叉树中,所有的父节点都小于两个子节点,这就是小顶堆
但是左右子节点不分大小,所以,树的根节点一定是最大或最小的。 -
将一个半有序的树变成大顶堆,部分有序化
如图的树,可以发现,根节点的左子树和右子树都有序,只是根节点不对,我们先将这种树,变成大顶堆。
1、比较左右两个结点,将最大的和父节点交换,此时,变成下图
2、可以发现,这次是和左边交换,并且,左子树的有序结构被改变,右边并没有改变,所以,我们应该继续在把以7为根结点的树,继续有序化。而右边的情况不会改变。
向左递归就可以完成。如下图。
3、代码实现//部分有序化函数 //参数,head,该节点,树中的节点数 void heap(int head,int n){ if(head>=n){ return; } int max=head; int c1=head*2+1; int c2=head*2+2; 记录最大值的下标 if(c1<n&&arr[c1]>arr[max]){ max=c1; } if(c2<n&&arr[c2]>arr[max]){ max=c2; } if(max!=head){ exchange(head,max);//交换这两个节点的值的函数 //和哪边交换,才有可能改变那边的结构,所以在对其有序化,使用递归 heap(max,n); } } //交换这两个节点的值的函数 void exchange(int a,int b){ int tmp; tmp=arr[a]; arr[a]=arr[b]; arr[b]=tmp; }
-
将一个任意的树,转成大顶堆;
任意一个树,变成大顶堆,只要从最后一个非叶子节点,依次向上,做部分有序化,直到根节点就可以,
1、如何找到从最后一个非叶子节点:其实他就是最后一个节点的父节点,使用上面的结论,最后一个非叶子节点=(n-1)/2;其他的依次递减,直到根节点,这样,就可以把任意一个树,转换成大顶堆。
2、代码实现``` //参数,n,当前树的结点个数 void build_heap(int n){ int tmp=(n-1)/2;//找到从最后一个非叶子节点 //依次递减到根节点 for(int i=tmp;i>=0;i--){ heap(i,n);//调用部分有序化的方法 } } ```
-
使用大顶堆排序
1、我们建成这样一个树,为什么?其实是想找到最大会最小的数,他一定位于根节点。
2、我们只要将他和最后一个交换,这时再将交之换后的树,去掉最后一个结点,在找到第二大的数,在放到最后,在去掉最后一个结点,直到结束。
3、这时,这个树的最大结点在最后,最小结点在最上面,这个完全二叉树有对应一个一维数组,这个一维数组,就是由小到大排列。void treeSort(){ build_heap(arr.length);//得到最大堆 //循环,i记录最后一个节点的下标,依次递减,就是依次将最后一个从树中去掉 for(int i=arr.length-1;i>=0;i--){ exchange(0,i);//交换根节点和最后一个结点 build_heap(i);//重新得到去掉最后一个结点后的最大堆 } }
完整的代码
//用来排序的类
class TreeArrSort{
int arr[];
//构造器,传入要排序的数组
TreeArrSort(int[] arr){
this.arr=arr;
}
void heap(int head,int n){
if(head>=n){
return;
}
int max=head;
int c1=head*2+1;
int c2=head*2+2;
if(c1<n&&arr[c1]>arr[max]){
max=c1;
}
if(c2<n&&arr[c2]>arr[max]){
max=c2;
}
if(max!=head){
exchange(head,max);
heap(max,n);
}
}
void exchange(int a,int b){
int tmp;
tmp=arr[a];
arr[a]=arr[b];
arr[b]=tmp;
}
void build_heap(int n){
int tmp=(n-1)/2;
for(int i=tmp;i>=0;i--){
heap(i,n);
}
}
void treeSort(){
build_heap(arr.length);
for(int i=arr.length-1;i>=0;i--){
exchange(0,i);
build_heap(i);
}
}
}
使用示意
public class TreeSort {
public static void main(String[] args) {
int arr[]=new int[]{5,8,7,4,3,7,54,7,23,6,7,2};//待排序数组
TreeArrSort tas=new TreeArrSort(arr);//排序类
tas.treeSort();//调用排序函数
//打印结果
for(int k:arr){
System.out.print(k+" ");
}
}
}
输出情况