堆排序

package arithmetic;
import java.io.PrintStream;
import java.math.*;
import java.util.Arrays;
/*
 * 	小顶堆的自适应程序
 * */
public class Heap {
	
	/*
	 * 	data	@ 待排序的数组
	 *  s		@ 除 data[s] 均满足堆的特性
	 *  n		数组的长度
	 * */
	public static void adjust(int data[],int s,int n)
	{
		int parent = s;//顶堆的结点
		int j = 2*parent;//其子结点
		while(j<n)
		{
			if(j+1<n&&data[j]>data[j+1])//取出两个子结点中的一个最小的
				j++;
			if(data[parent]>data[j])//把子结点中最小的那个与其父亲结点的值比较,如果小,与父亲结点交换
			{
				int temp = data[parent];
				data[parent] = data[j];
				data[j] = temp;
				parent = j ;//父亲结点为当前的结点
				j = 2*j;//当前结点下移
			}else
			{
				break;
			}
		}
	}
	/*
	 * 	这个利用完全二叉树的一个很重要的性质:最后一个非叶子结点为 第 n/2个
	 * 	1.从最后一个非叶子结点开始,把其代表的堆都自适应成一个极小堆0
	 * 	2.然后从整个堆的最后一个元素开始,与堆顶交换,然后再自适应成一个堆
	 * */
	public static void sort(int data[],int n)
	{
		for(int i=n/2;i>0;i--)
		{
			adjust(data,i,n);
		}
		for(int i=n-1;i>0;i--)//从堆的最后一个元素开始
		{
			int temp = data[1];
			data[1] = data[i];
			data[i] = temp;//交换数据后自适应成堆 
			adjust(data,1,i);
		}
	}
	public static void main(String args[]) throws Exception
	{
		
		int data[] = {0,35,18,20,65,40,46,58,25};// 0 为填充数 data[0] 无用,使节点下标从1开始
		int test[] = new int[1000];
		for(int i=999;i>0;i--)
		{
			test[i] = i;
		}
		
		System.setOut(new PrintStream("F:\\test.txt"));
		sort(test,1000);
		for(int i=1;i<1000;i++)
			System.out.println(test[i]);
	}
}

/*
 * 
 * 				堆排序
 * 		小顶堆:堆顶点的值比两个叶子节点的值都要小,把子节点还可以看作一个堆,也满足以上面条件 
 * 		堆排序思路:
 * 			1.先将待排序的数据存入在数组中
 * 			2.将数据利用筛选法创建成一个小顶堆
 * 			3.取出当前小顶堆的堆头与叶子结点的最后一个交换,后又形成一个不符条件的堆
 * 			4.然后再利用筛选法将不符全条件的堆适应成一个符和条件的堆
 * 
 * 
 * 			筛选法:
 * 				从当前堆顶元素不满足堆的条件,其余都满足的堆顶点开始
 * 				拿其与其两个叶子结点中比较小的相比较,如果堆顶元素比它们的结果大,
 * 				那么就要拿堆顶元素与叶子结点中比较小的那个交换,从而使自己又达到一个堆
 * 				而对于其子叶结点也是使用相同的方法
 * 		有一个问题:为什么在构建堆的过程中,要从下到上构造,也就是为什先选择最后一个非叶子结点[n/2]?而不是从第一结点开始
 * 		答:在排序的时候,我们是在一个极小顶堆的基础上拿去了一个堆顶的元素,而下面的堆都是符合堆的条件的,只有第一个不符合,
 * 			而当我们构建堆的时候,也是用的这种方法,我们找到一个只有顶堆不符合堆的条件后,然后再进行适应,而
 * 			在一个错乱的数据里怎么才能找到一个只有顶堆不符合条件的结点,这个很难办,那我们就认为所有的叶子结点
 * 			都符合极小堆的条件,而对于第一个非叶子结点,我们就不能保证,我们我们就从最后一个非叶子结点开始构建
 * */
 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值