前置知识:
1.二叉堆:(1)是完全二叉树或近似完全二叉树(2)父节点键值均大于子节点键值或父节点键值均小于子节点键值(3)子树也是二叉堆
2.大顶堆:父节点键值均大于子节点键值的二叉堆
3.小顶堆:父节点键值均小于子节点键值的二叉堆
堆排序思路:
给定了一个杂乱无章的数组,可以将其转化成一个完全二叉树或近似完全二叉树。然后再堆化(可以转成大顶堆也可以转化成小顶堆);以大顶堆为例:大顶堆顶点元素必然是所有元素中最大的,先将其与当前数组(也是当前大顶堆最后一个元素)进行交换;交换完之后数组最后一个元素为所有数中最大值;除去此时二叉堆最后一个元素(最大值)再进行大顶堆化,一直循环到最后一个元素,这便是一次次将本趟最大值放到了本趟数组最后位置,也就排好了序。
堆排序步骤:
1.大顶堆化或小顶堆化
2.排序
大顶堆化为例:
public class 堆排序 {
public static void main(String[] args) {
int []a= {12,7,11,3,6,8,9};
HeapSort(a);//堆排序
System.out.println("堆排序后");
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+" ");
}
}
private static void HeapSort(int[] a) {
// TODO Auto-generated method stub
//1.堆化成大顶堆
MaxHeap(a);
int n=a.length;//数组长度
//2.排序
for(int i=n-1;i>=0;i--)
{
int term=a[i];
a[i]=a[0];
a[0]=term;
MaxHeapFixDown(a, 0, i);//向下堆化
}
}
//大顶堆化
private static void MaxHeap(int[] a) {
// TODO Auto-generated method stub
int n=a.length;
for(int i=n/2-1;i>=0;i--)//从倒数第二层的最后一个节点开始往上不断调整,因为最底的一层是叶子节点,不需要调整
{
MaxHeapFixDown(a,i,n);
}
}
//大顶堆化向下调整
private static void MaxHeapFixDown(int[] a, int i, int n) {
// TODO Auto-generated method stub
int left=2*i+1;//左儿子
int right=2*i+2;//右儿子
if(left>=n)
{
return;//下标越界,意味着没有儿子
}
//走到这里了,意味着有左儿子
int max=left;//暂时定此时两者中数值较大的是左儿子下标
if(right>=n)
{
max=left;//此时不存在右儿子,所以两者中较大的那个数的下标是左儿子---------实锤
}
else {//此时左右儿子都存在
if(a[right]>a[left])
{
max=right;//如果右儿子大,便取代max
}
}
//至此,儿子中数值最大的儿子已经求出
if(a[max]>a[i])//儿子中较大的那个与本来顶部比较,有比顶部大的才交换
{
int term=a[i];
a[i]=a[max];
a[max]=term;
}
MaxHeapFixDown(a, max, n);//递归地将此棵树下面的子树也调整一下,因为你调换之后,只能保证最近的三个节点满足大顶堆
}
}

小顶堆化
public class 堆排序2 {
public static void main(String[] args) {
int []a= {12,7,11,3,6,8,9};
HeapSort(a);
System.out.println("堆排序后");
for(int i=a.length-1;i>=0;i--)
{
System.out.print(a[i]+" ");
}
}
private static void HeapSort(int[] a) {
// TODO Auto-generated method stub
MinHeap(a);
int n=a.length;
for(int i=n-1;i>=0;i--)
{
int term=a[i];
a[i]=a[0];
a[0]=term;
MinHeapFixDown(a, 0, i);//每次都是从0开始向下堆化
}
}
//小顶堆化
private static void MinHeap(int[] a) {
// TODO Auto-generated method stub
int n=a.length;
for(int i=n/2-1;i>=0;i--)
{
MinHeapFixDown(a,i,n);//向下小顶堆化
}
}
private static void MinHeapFixDown(int[] a, int i, int n)
{
// TODO Auto-generated method stub
//先找左右孩子
int left=2*i+1;
int right=2*i+2;
if(left>=n)//没有左孩子
{
return;
}
int min=left;//目前暂定两个儿子当中最小下标是左孩子
if(right>=n)
{
min=left;
}
else
{
if(a[right]<a[left])
{
min=right;
}
}
//到此已经找到了两个儿子中较小的那一个的下标
if(a[min]<a[i])
{
int term=a[min];
a[min]=a[i];
a[i]=term;
}
//交换之后,当前以i为父节点的子树便成了小顶堆
MinHeapFixDown(a, min, n);//看看min为父节点的树是否满足小顶堆,继续递归调整
}
}


1434

被折叠的 条评论
为什么被折叠?



