• 堆排序算法剖析


    1.将待排序列以一个完全二叉树存储,设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层所有的结点都连续集中在最左边,这就是完全二叉树。

      

    2.第一趟排序,从二叉树的最后一个根节点(有步骤1可知是值为12的节点)开始,调整当前节点所在的堆,使当前节点大于所有子节点的值,最终得到的堆是最大根堆。

    (1)12->36

    (2)73->81

    (3)49->98

    (4)55->81->73

    (5)40->98->49

    3.第二趟排序,每趟排序后,待排序列中的最大值将被移动到根节点,将根节点元素与待排序列中最后一个元素交换位置,红色元素表示已经排好的序列,红色元素不参与下轮的排序过程

    (1)98->12

    (2)12->81->73->64

    (3)81->12

    (4)12->73->64->55

    (5)73->12

    (6)12->64->55

    (7)64->40

     

    (8)40->55

    (9)55->27

    (10)27->49

    (11)49->36

    (12)36->40

    (13)40->12

    (14)12->36

    (15)36->27

     

    (16)27->12

    (16)12->12

    代码:

    package com.zjl.tool.sort;
    
    /**
     * 堆排序
     * @author huanongying
     *
     */
    public class HeapSort {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            int[] arr = {40,55,49,73,12,27,98,81,64,36};//待排序数组
            HeapSort(arr, arr.length - 1);//将arr按照降序排列
            //打印排序后的数组
            for(int value : arr) {
                System.out.print(value + " ");
            }
        }
    
        /**
         * 待排序列(R1,R2,...,Rk,...Rn)看作是完全二叉树,通过比较、交换,父节点和孩子节点的值,
         * 使得对于任意元素Rk(k<=n/2),满足Rk>=R(2k),Rk>=R(2k+1)
         * @param arr    数组对象
         * @param start    数组的开始下标
         * @param end    数组的结束下标
         */
        private static void HeapAdjust(int[] arr, int start, int end) {
            //当下标为start的元素有孩子元素时
            while(start <= end/2) {
                //left和right分别为左右孩子元素的下标,max为左右孩子中值较大的孩子的元素下标
                int left = 2 * start+1;
                int right = 2 * start+2;
                int max = 0;
                
                //如果既有左孩子,又有右孩子
                if(left < end&&right <= end) {
                    //如果左孩子小于右孩子的值,max = right,否则为max = left
                    if(arr[left] <= arr[right])
                        max = right;
                    else
                        max = left;
                }
                //如果只有左孩子,没有右孩子,max值为left
                if(left <= end&&right > end) {
                    max = left;
                }
                //如果没有孩子,则表明到了完全二叉树的叶子节点
                if(left > end) {
                    break;
                }
                
                //如果当前节点值小于两孩子中的值较大者,那么将当前节点值与max交换
                if(arr[start] < arr[max]){
                    int tmp = arr[start];
                    arr[start] = arr[max];
                    arr[max] = tmp;
                }
                //当前节点向孩子节点迭代
                start = max;
            }
        }
    
        /**
         * @param arr 数组
         * @param end    数组结束下标
         */
        private static void HeapSort(int[] arr, int end) {
            //由最后一个非叶子节点,向根节点迭代,创建最大堆,数组中的最大值将被移动到根节点
            for(int start = end/2;start >= 0;start--) {
                HeapAdjust(arr, start, end);
            }
            
            while(end > 0){
                //交换arr[0]和arr[end]的值
                int tmp = arr[0];
                arr[0] = arr[end];
                arr[end] = tmp;
                
                //排序范围变为(0,end-1)
                HeapAdjust(arr, 0, end - 1);
                end--;
            }
        }
    
    }


     

  • 相关阅读:
    16款值得一用的iPhone线框图模板 (PSD & Sketch)
    设计神器
    {CF812}
    hiho1080(多标记线段树)
    {容斥原理}
    {dp入门}
    {AC自动机}
    CF807
    Trie树
    杂记
  • 原文地址:https://www.cnblogs.com/huanongying/p/7622168.html
Copyright © 2020-2023  润新知