堆排序

本文详细介绍了堆排序的基本概念,包括堆的特性、如何构建大顶堆与小顶堆,并通过具体的实例展示了堆排序的过程。此外,还提供了完整的Java代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

               (1)堆的特性

                          1.根节点的值总是大于任何一个子节点的值(大顶堆)

                          2.每一个节点的左子树和右子树都是一个堆

                          注意:对左右子树谁大谁小没有要求

                 


               (2)建堆

                          1.有如下的数组,初始情况下的堆为下图

              int[] a = {9,12,17,30,50,20,60,65,4,19};

                       


                          2.因为叶子节点可以视为已经就是堆了,所以根本不用整个调整,只用从第一个非叶子节点向下调整即可(如果根为0,那么第一个非叶子节点下标为n/2-1,n为节点总数)

                          3.向下调整

                             对于小顶堆,下标从0开始,则节点i的左孩子下标为2*i+1,右孩子为2*i+2

	public void fixDown(int[] a, int parent,int lastIndex)
	{
		int temp = a[parent];
		int child = parent*2+1;
		
		while(child<=lastIndex)
		{
			if(child+1<=lastIndex && a[child]>a[child+1])
				child++;//找出左右孩子中的较小者
			
			if(temp<a[child])//如果调整的节点的值比左右孩子都小,那么说明这就是最终位置
				break;
			else
			{
				a[parent] = a[child];
				parent = child;
				child = parent*2+1;
			}
		}
		a[parent] = temp;//必须不能少
	}
                    
                          4.建堆

                int[] a = {9,12,17,30,50,20,60,65,4,19};
		
		for(int i=a.length/2-1; i>=0; i--)
			fixDown(a,i,a.length-1);
                            结果为:

                           


               (3)排序

                          建堆之后,第一次将a[0]与a[n-1]交换,再对a[0...n-2]恢复堆(其实也就是将a[0]向下调整,且最后一个元素就不参与调整了)。第二次将a[0]与a[n-2]交换,再对a[0...n-3]恢复堆(其实也就是将a[0]向下调整,且最后两个元素就不参与调整了)。以此类推,直至a[0]与a[1]交换。因为每次都是将最小的放入后面的有序区间前面,所以操作完成之后整个数组就有序了。

		int[] a = {9,12,17,30,50,20,60,65,4,19};
		
		for(int i=a.length/2-1; i>=0; i--)
			fixDown(a,i,a.length-1);
		
		for(int i=a.length-1; i>=0; i--)
		{
			int temp = a[i];
			a[i] = a[0];
			a[0] = temp;
			
			fixDown(a, 0,i-1);
			
		}
		for(int x:a)
			System.out.print(x+" ");
                         结果为:

65 60 50 30 20 19 17 12 9 4 
                         因为建立的是小顶堆,所以排出来的递减序列,如果需要改为正序,那么改为大顶堆即可,其他不用变。

                        大顶堆的fixDown

	public void fixDown(int[] a, int parent,int lastIndex)
	{
		int temp = a[parent];
		int child = parent*2+1;
		
		while(child<=lastIndex)
		{
			if(child+1<=lastIndex && a[child]<a[child+1])
				child++;
			
			if(temp>a[child])
				break;
			else
			{
				a[parent] = a[child];
				parent = child;
				child = parent*2+1;
			}
		}
		a[parent] = temp;
	}
                      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值