排序算法之堆排序


title: 排序算法之堆排序
date: 2019-09-02 09:59:27
tags: -堆排序

算法思想:
  • 完全二叉树是除了最后一层,每层都铺满,且最后一层是从左到右铺的。堆也是完全二叉树。

在这里插入图片描述

因为是完全二叉树,所以可以利用其下标特性使用数组进行操作。

由于任意数组肯定不满足父节点大于其子节点的值这一特性。所以要将该数组进行初始化堆。

  • 初始化堆(InitHeap())需要从该树的**最后一个非叶节点(array.length/2-1)**进行。从该节点进行向下调整(AdjustHeap()),注意调整完后的子堆会由于调整后变得不是大顶堆,需要继续调整。如下图所示。
    在这里插入图片描述

root = maxchildIndex,然后再进行循环。(循环条件是只循环非叶节点,因为也叶节点不存在子节点,不会出现其子节点值大于自身值的情况。)

  • 初始化完堆后就已经使数组满足了父节点的值大于子节点的值这一条件了。此时array[0]中就是当前数组中的最大值,将array[0]和当前数组的最后一个元素a[array.length-1]交换,此时当前数组的最后一个元素就是当前数组的最大值。然后将剩余的a[0]-a[array.length-2]继续进行堆调整。调整后再将a[0]和a[array.length-2]进行交换,重复该过程,这样就得到了排序后的数组。

  • 需要注意的是,最开始进行堆调整是为了使数组满足了父节点的值大于子节点的值这一条件,是从最后一个非叶节点向上进行调整的。

  • 将a[0]和a[array.length-1]交换后,对a[0]-a[array.length-2]进行堆调整是从a[0]向下进行调整的。

  • 判断最后一个非叶节点是只有左孩子还是左右孩子都有。

    if((root == length/2-1) && (length % 2 == 0))

  • 先在子节点之间比较,大的和父节点进行交换。

    package Select;
    public class Heap_sort {
    
    	public static void main(String[] args) {
    		NewArray array = new NewArray();//这样就随机生成了一个有十个成员的数组
    		int[] a = array.Array();
    		System.out.println("初始状态");
    		Display(a);
    				
    		HeapSort(a);
    		System.out.println("排序之后");
    		Display(a);
    
    	}
    	
    	private static void HeapSort(int[] array)
    	{
    		InitHeap(array);
    		int count = array.length;
    		while(count>=2)
    		{
    			int temp = array[count-1];
    			array[count-1] = array[0];
    			array[0] = temp;
    			
    			count--;
    			AdjustHeap(array,count,0);
    		}
    	}
    	
    	private static void InitHeap(int[] array)
    	{
    		for(int i = array.length/2-1;i>=0;i--)
    		{
    			AdjustHeap(array,array.length,i);
    		}
    	}
    	
    	private static void AdjustHeap(int[] array,int length,int root)
    	{
    		while(root <= length/2-1)//length-1是数组最后一个元素的下标号
    		{
    			int maxChildIndex;
    			if((root == length/2-1) && (length % 2 == 0))//需要判断最后一个非叶节点是否是两个孩子都有,如果有偶数个节点,只有左孩子。
    			{
    				maxChildIndex = root*2+1;
    			}
    			else
    			{
    				int leftchildIndex = root*2+1;
    				int rightchildIndex = root*2+2;
    				maxChildIndex = array[leftchildIndex] > array[rightchildIndex] ? leftchildIndex:rightchildIndex;
    			}
    			if(array[maxChildIndex]>array[root])
    			{
    				Swap(array,maxChildIndex,root);
    				root = maxChildIndex;//继续循环,保证调整后堆的子堆仍是是符合大顶堆,且这种由于交换完元素,子堆出现不符合大顶堆的现象只可能发生在非叶节点上,也就是root<=length/2-1
    			}
    			else
    			{
    				return;//该root下的左右孩子和root无需调整
    			}
    		}
    	}
    	
    	private static void Swap(int[] array,int a,int b)
    	{
            /*交换时因该带上数组,不然值根本不改变*/
    		int temp;
    		temp = array[a];
    		array[a] = array[b];
    		array[b] = temp;
    	}
        
        	//private static void Swap(int a,int b)
    	//{
            //交换时因该带上数组,不然数组值根本不改变
    		//int temp;
    		//temp = a;
    		//a = b;
    		//b = temp;
    	//}
    	
    	private static void Display(int[] array)
    	{
    		for(int i = 0;i<array.length;i++)
    		{
    			System.out.print(array[i]);
    			System.out.print(" ");
    		}
    		System.out.println();
    	}
    
    }
    
    
package Select;
import java.util.Random;
public class NewArray {
	public static int[]  Array()
	{
		Random random = new Random();
		int[] a = new int[10];
		for(int i = 0;i<a.length;i++)
		{
			a[i] = random.nextInt(100);
		}
		return a;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值