zoukankan      html  css  js  c++  java
  • 最大(小)堆和堆排序简介

    (注:本文的相关叙述和图片摘自《数据结构与算法分析新视角》(周幸妮等),因此本文只是我的一个复习记录,详细的论述请参考该书。)

    1. 最大(小)堆

      对于一个完全二叉树来说,如果所有的结点(叶子结点除外)的值都大于(小于)其左右孩子结点的值,那么这个完全二叉树就被成为一个大(小)根堆。如下图所示。按照堆的定义可以发现,堆顶结点(二叉树的根结点)一定对应整个序列中的最大(小)记录。这样一来,可以设计一种排序思路,每次将堆的堆顶记录输出,同时调整剩余的记录,使它们从新排成一个堆。重复这个过程,就能最终得到一个有序的序列,完成排序的过程,这种方法称之为堆排序。

      因此,对于堆排序来说,主要有两个问题:

    • 一个无序序列的所有记录如何排列成一个堆?
    • 在输出了堆顶记录后,如何将剩下的记录再排成一个堆?

    2. 堆排序

    • 由无序序列生成堆

      以序列{49,38,65,97,76,13,27,49,55,04}为例,介绍生成最小堆的思路。我们知道一棵完全二叉树的最后一个非叶子结点的索引为[n/2],因此在本例中,选择第5个记录{76}作为初始筛选点。首先比较{76}与其左右孩子结点记录的大小,并按照筛选的结果进行交换,因此得到下图2的结果。接下来对倒数第二个非叶子结点进行处理,结果如下图3所示。重复这个步骤,可以得到一个结构完整的最小堆,如下图4所示。

                

                                              (1)序列直接构成完全二叉树       (2)一次筛选之后的完全二叉树      (3)二次筛选之后的完全二叉树

     

    (4)经过多次筛选之后的最小堆

    • 堆排序

      以序列{13,38,27,49,76,65,49,97}为例,介绍堆排序的思路。

                                  初始堆                                              输出堆顶元素后的情形

                       最后一个记录暂放于堆顶                                      一次调整之后的情形

                          二次调整之后的情况                                输出记录{27}之后再排成一个堆

       重复上述步骤,最终就可以生成一个有序序列。

     3. 相关代码

    • 生成最大堆代码(最小堆类似)
     1 //调整堆结点 
    2
    //arr:数组首地址;n:结点在数组中的位置;len:数组的长度 3 void adjust_node(int *arr, int n, int len) 4 { 5 int l, r, max, tmp; 6 l = 2 * n + 1; //左右孩子的索引,注意数组下标从0开始。 7 r = 2 * n + 2; 8 max = n; 9 10 if (l<len&&arr[l]>arr[n]) 11 max = l; 12 if (r<len&&arr[r]>arr[max]) 13 max = r; 14 15 if (max != n) 16 { 17 tmp = arr[n]; 18 arr[n] = arr[max]; 19 arr[max] = tmp; 20 adjust_node(arr, max, len); //保证最大堆 21 } 22 }
    • 堆排序
     1 //堆排序(升序)
     2 void sort_heap(int *arr, int len)
     3 {
     4     for (int i = len / 2; i >= 0; i--)
     5         adjust_node(arr, i, len);
     6     int tmp;
     7     for (int i = len - 1; i >= 0; i--)
     8     {
     9         tmp = arr[0];
    10         arr[0] = arr[i];
    11         arr[i] = tmp;
    12         adjust_node(arr, 0, i);
    13     }
    14 }
    • 验证
     1 #include <iostream>
     2 using namespace std;
     3 
     4 int main()
     5 {
     6     int arr[] = { 49,38,65,97,76,13,27,49,55,04 };
     7     int len = 10;
     8 
     9     for (int i = 0; i < len; i++)
    10         cout << arr[i] << ' ';
    11     cout << endl;
    12 
    15     sort_heap(arr, len);
    16 
    17     for (int i = 0; i < len; i++)
    18         cout << arr[i] << ' ';
    19     cout << endl;
    20 
    21     return 0;    
    22 }

    输出结果:

    49 38 65 97 76 13 27 49 55 4
    4 13 27 38 49 49 55 65 76 97

  • 相关阅读:
    解决 Mac launchpad 启动台 Gitter 图标无法删除的问题
    React 与 React-Native 使用同一个 meteor 后台
    解决 React-Native mac 运行报错 error Failed to build iOS project. We ran "xcodebuild" command but it exited with error code 65. To debug build logs further, consider building your app with Xcode.app, by ope
    一行命令更新所有 npm 依赖包
    swift学习笔记
    IOS语言总结
    focusSNS学习笔记
    别小看锤子,老罗真的很认真
    windowsphone开发页面跳转到另一个dll中的页面
    【令人振奋】【转】微软潘正磊谈DevOps、Visual Studio 2013新功能、.NET未来
  • 原文地址:https://www.cnblogs.com/jmliao/p/6706762.html
Copyright © 2011-2022 走看看