java实现堆排序

前置知识:
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为父节点的树是否满足小顶堆,继续递归调整
}
}



在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值