zoukankan      html  css  js  c++  java
  • 排序算法之堆排序

    堆的结构可以分为大根堆和小根堆,是一个完全二叉树,而堆排序是根据堆的这种数据结构设计的一种排序。

    大根堆:每个结点的值都大于其左孩子和右孩子结点的值。所以对任一棵子树:根节点的值都是最大的。

    小根堆:每个结点的值都小于其左孩子和右孩子结点的值。所以对任一棵子树:根节点的值都是最小的。

    堆可以采用数组存储,结点的标号从 $0$ 开始,则对任一个结点 $i$,其左孩子的结点标号为 $2i+1$,右孩子的结点标号为 $2i+2$。

    下面以大根堆为例,介绍堆排序的基本步骤。

        1)首先将待排序的数组构造成一个大根堆,此时,整个数组的最大值就是堆结构的顶端。

        2)将顶端的数与末尾的数交换,此时,末尾的数为最大值,剩余待排序数组个数为 $n-1$。

        3)将剩余的 $n-1$ 个数再构造成大根堆,再将顶端数与 $n-1$ 位置的数交换,如此反复执行,便能得到有序数组(一开始就是数组存储的)。

    可见这个算法最重要的操作就是:将树调整为大顶堆。

    对某个子树进行堆化(Heapify)的前提是:除自身外,该子树的任一棵子树都满足大顶堆结构。

    因为 BuildHeap 的过程是自底向上,所以将一棵乱序的树调整为大顶堆的过程可以调用 Heapify,换句话说:将一棵树调整

    为大顶堆之前,其任一棵子树就都已经被调整为大顶堆了。

    /*
     * n: 树的结点总数
     * i: 对以 i 为根节点的子树做堆化操作
     * 之所以可以使用递归,必须有一个前提条件: 树 i 的任一棵子树都是大顶堆。
       这样至上而下的调整时只需考虑下面的堆结构是否被破坏,而不用担心上面的结构是否被破坏。
     */
    void Heapify(int tree[], int n, int i)
    {
        if (i >= n) return;
    
        int c1 = (2 * i) + 1;
        int c2 = (2 * i) + 2;
        int max = i;
    
        if (c1 < n && tree[c1] > tree[max]) {
            max = c1;
        }
        if (c2 < n && tree[c2] > tree[max]) {
            max = c2;
        }
        // 孩子结点的值比父节点的大,需要交换
        if(max != i) {
            swap(tree[max], tree[i]);
            // 被交换后的子节点,其堆结构可能被破坏,继续向下调整
            Heapify(tree, n, max);
        }
    }
    
    void BuildHeap(int tree[], int n)
    {
        int last_node = n - 1;
        int parent = (last_node - 1) / 2;
    
        // 因为是从下到上调整的,所以满足 Heapify 的那个前提
        for(int i = parent; i >= 0; --i) {
            Heapify(tree, n, i);
        }
    }
    
    void HeapSort(int tree[], int n)
    {
        // 先调整成一个堆
        BuildHeap(tree, n);
    
        for(int i = n - 1; i >= 0; --i) {
            swap(tree[0], tree[i]);
            Heapify(tree, n - 1, 0);
        }
    }
  • 相关阅读:
    51,智联,猎聘,boss 15
    ubuntu重命名[桌面]为[desktop]
    13周让你爱上跑步-计划表
    Typecho的安装 --【Typecho01】.md
    ubuntu跑vue报错:#Error from chokidar # Error: ENOSPC: System limit for number of file watchers reached
    Java中多线程编程--synchronized关键字
    Java中几种常见的设计模式--代理设计模式
    Metaspolit下UAC提权以及日志清除
    JVM初探(五):类的实例化
    JVM初探(四):类加载器
  • 原文地址:https://www.cnblogs.com/yanghh/p/13698675.html
Copyright © 2011-2022 走看看