• 算法:堆排序



    堆排序可归纳为两个操作:

    1)建堆:根据初始数组去构造初始堆(构建一个完全二叉树,保证所有的父结点都比它的孩子结点数值大)。

    2)调整堆:每次交换第一个和最后一个元素,输出最后一个元素(最大值),然后把剩下元素重新调整为大根堆。 当输出完最后一个元素后,这个数组已经是按照从小到大的顺序排列了。调整堆的过程是:比较节点i和左右节点,选出三者最大的,如果是孩子节点,那么交换;并继续比较。

    建大根堆:buildMaxHeap(a[])

    从A.length / 2一直到根结点进行堆调整。

    堆调整:adjustHeap(a[], parent, length);

    • 定义左孩子child = 2 * parent + 1;tmp保存父节点;
    • 当child < length 的时候:
      • 如果有右孩子并且右孩子大于左孩子,则选取右孩子;(选择孩子中较大的;)
      • 如果父节点值>孩子节点 break;(父>子,调整完毕;)
      • 孩子节点的值赋给父节点;(调整父和孩子;)
      • 孩子index赋给父index;并继续child的孩子index赋给孩子index(继续向下调整;)
    • tmp赋给最后的父节点;(找到调整值得最终位置;)

    堆排序:heapSort(a[])

    • 建最大堆;
    • for(i=n-1)循环n-1次,交换首尾;adjustHeap(a, 0, i);

    辅助交换:swap(a[], i, j)

    参考代码:

    public class Solution {
        /**
         * @param A an integer array
         * @return void
         */
         //堆排序
        public void sortIntegers(int[] a) {
            if (a.length == 0) return;
            buildMaxHeap(a);
            for (int i = a.length - 1; i > 0; i--) {
                swap(a, i, 0);
                adjustHeap(a, 0, i);
            }
        }
        
        public void buildMaxHeap(int[] a) {
            for (int i = a.length/2; i >= 0; i--) {
                adjustHeap(a, i, a.length);
            }
        }
        
        
        public void adjustHeap(int[] a, int parent, int length) {
            int tar = a[parent];
            int child = parent * 2 + 1;
            while (child < length) {
                if (child + 1 < length && a[child] < a[child + 1]) child++;
                if (a[child] < tar) break;
                a[parent] = a[child];
                parent = child;
                child = child * 2 + 1;
            }
            a[parent] = tar;
        }
        
        public void swap (int[] a, int i, int j) {
            int tmp = a[i];
            a[i] = a[j];
            a[j] = tmp;
        }
        
    }
    • adjustHeap(a, parent, length):
      • tar值保存a[parent];定义child;
      • 当chile<length:
        • 获取左右孩子中较大的:若存在右孩子且大于左孩子则child++;
        • 比较child和tar:若已经满足[tar]>[child]则break;
        • child值赋给parent:注意这里是赋值而不是swap;
        • 继续向下调整:parent变化,child变化;
      • tar值赋给最终的a[parent];
    • buildMaxHeap(a):
      • for(i=a.length/2; i>=0),adjustHeap(a,i,a.length);注意参数是length;循环范围是[0,a.length/2];
    • heapSort(a):
      • 判断空return;
      • 建堆buildHeap(a);
      • 循环n-1次调整堆for(i=a.length-1; i>0); 循环范围是(0,length-1]n-1次;
        • swap(a,i,0);
        • adjustHeap(a,0,i) length的范围是[0,n-1]也就是i;
    • swap(a[],i,j);

    参考:堆排序

    测试数据:LintCode--Sort Integers 


  • 相关阅读:
    百万英雄答题值不值得您继续参加
    一个程序员&自媒体人的2017年终总结
    送书福利又来了,总共10本程序员技术书
    CCF 201912-2 回收站选址(100分)Java
    CCF 201912-1 报数 (100分)Java
    CCF 201909-2 小明种苹果(续)(100分)Java
    CCF 201909-1 小明种苹果(100分)Java
    初识JWT
    Redis学习——事务、消息订阅和发布
    Redis学习——数据类型及操作
  • 原文地址:https://www.cnblogs.com/buwenyuwu/p/7219576.html
Copyright © 2020-2023  润新知