简单易懂堆排序

来源:互联网 发布:全球人工智能市场规模 编辑:程序博客网 时间:2024/05/20 13:05

# 什么是堆?

  1.堆是一个完全二叉树

  2.任意非叶子节点的值大于等于(大顶堆)或小于等于(小顶堆)其左右孩子的值.


   这就说明根元素的值是堆中最大或最小的.


   

      如果我们输出堆顶元素, 然后对剩下的元素重新调整为一个堆, 如此直到输出所有元素, 便可完成排序了.

      但是有个问题, 初始给定的数据不是一个堆啊, 所以我们要先将其初始化为堆.


      因此, 实现堆排序需要解决两个问题: 1. 将一个无序序列构建为一个堆        2.输出堆顶元素后, 调整堆.


# 通常的结构

   物理结构为一个数组, 逻辑结构为完全二叉树.

   用 n 表示最大下标则:

   array[0] 为堆顶

   array[i] 的左孩子为 array[2*i+1], 右孩子为 array[2*i+2]          i >= 0 && i <= (n-1)/2


# 堆排序过程

   1. 怎么构建一个堆呢?

       也就是说我们要将一个最大/最小的元素放到堆顶

       那就在堆顶 array[0], 左子树 array[1], 右子树 array[2] 中"选择"一个最大的放到 array[0]

       那左子树 array[1] 的最大元素呢? 我想聪明的你应该想到了, 继续同样的操作就行了.

       这里的"选择"就是一个调整堆的过程. 所以现在我们将问题转化为调整堆了.

   2. 调整堆

       我们给定序列 8, 9, 6, 7, 9, 7

       创建的大顶堆如下, 这时 array[0] 即为此序列的最大元素

       输出堆顶元素(和序列最后一个元素交换位置)

 

     这时就破坏了大顶堆, 我们先调整(6, 9, 7), 选择一个最大的与根交换

     由于交换又破坏了左子树, 那就继续调整, 直到所以遭破坏的树调整完毕即可

     有可能破坏的树只有交换后的子树.

           输出堆顶元素(交换), 此时堆顶元素为序列中次大的元素

              同样调整堆

           继续输出

          调整

            交换输出

         调整

           交换输出, 只剩下一个元素, 此时排序完成

          如此, 我们可以看出大顶堆完成是从小到大的排序

          稍微想一下, 小顶堆则完成的是从大到小的排序


      此时我们再看创建大顶堆的过程, 就比较清楚了. 依次队非叶子节点调整


  # 代码

static void adjust_heap(int *keys, int first, int last) {    int root, child;        // child 开始为左孩子    for (root = first; (child = root * 2 + 1) <= last; root = child) {        // 在左右孩子中选择一个最大的, 此时最大的元素下标为 child        if (child + 1 < last && keys[child+1] > keys[child]) {            child = child + 1;        }        // 如果孩子中最大的比父节点大, 则与父节点交换, 并以此孩子节点为根继续调整 root = child        if (keys[child] > keys[root]) {            swap(&keys[child], &keys[root]);        // 如果在没交换的情况下, 父节点就是最大的, 则无需再继续调整        } else {            break;        }    }}          void heap_sort(int *keys, int len) {          int i;                // 使len为最大索引          len -= 1;                // 构造大顶堆, 此时保证 keys[0] 为最大元素          for (i = (len-1)/ 2; i >= 0; --i)              adjust_heap(keys, i, len);                    for (i = len; i > 0; ) {              // 将 keys[0] 放到尾部,              swap(&keys[i], &keys[0]);                    // 移除最大元素, 调整堆               adjust_heap(keys, 0, --i);          }      }  


0 0
原创粉丝点击