0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

STL中的堆算法该如何使用呢?

算法与数据结构 来源:暮回_zz 2023-04-19 16:42 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

堆结构简述

了解过数据结构的人,应该对堆结构不陌生,堆的底层是使用数组来实现的,但却保持了二叉树的特性。堆分为两种,最大堆和最小堆,以最大堆为例,最大堆保持了根结点大于两个左右两个孩子,同时所有子树一次类推。由于堆底层是数组结构,这里从跟结点开始,按照层序依次走到最后一个结点,结点下标分贝为0~N-1。结构如下图:

d5058e90-de8d-11ed-bfe3-dac502259ad0.png

上图中,紫色表示的是该元素在数组中的下标,可以看到,每个结点的值总是大于它的左右孩子,这里并没有规定左右孩子的大小关系,也没有规定不是同一棵树之间结点的大小关系。这就是最大堆。同时这里可以注意到,如果是大堆,根节点一定是树中最大的结点,同样,如果是小堆,根节点一定是树中最小的结点。

堆结构在排序领域,占据着一定的低位,但是STL中并没有直接给出堆结构,而是把堆的相关算法,写在了 algorithm 里面。在这里我不会过多的去模拟实现一个堆,今天要说的是关于STL中给出的堆算法如何使用。

algorithm 中的堆算法

在STL中,关于堆,给出了一下几种算法。

★make_heap

★push_heap

★pop_heap

★sort_heap

这里,首先给出一个利用STL中堆算法的实例

#include   
#include   
void test()  
{  
  int arr[] = {1,2,3,4,5,6,7};  
  vector vec(arr, arr+7);     // 左开右闭类型  
  make_heap(vec.begin(), vec.end());  // 默认建大堆  
  pop_heap(v1.begin(), v1.end());     
  v1.pop_back();             
  sort_heap(vec.begin(), vec.end());  // 堆排序  
  for(size_t i = 0; i < vec.size(); i++)   
        cout<

上面代码,首先用一个数组构建了一个向量,之后对向量vec建堆,pop出调整之后的向量中第一个元素,并进行调整,然后进行堆排序,最后将结果打印出来,打印结果如下:

d516c020-de8d-11ed-bfe3-dac502259ad0.png

看完了heap算法的基本使用,现在,我们了解一下,STL中是如何提供这些算法接口的。

1、make_heap

d52d72f2-de8d-11ed-bfe3-dac502259ad0.png

前面提到过,堆分为大堆和小堆,我们建立堆的时候就需要确定,但刚刚例子中,我们并没有去指定大小堆。STL中规定,没有指定的话,默认大堆结构。从上面关于make_heap的两套接口可以看到,第一种是默认的,没有提供指定大小堆的接口,第二种这里有实现。我们可通过仿函数的结构,实现这里的传参。

对刚刚给出的例子,我们现在可以解释另外一个问题,为什么我们要进行堆排序,首先要构建vector呢?因为堆的底层实现就是通过数组的形式,而vector是堆数组的高级封装,这些库中实现好的容器给出了很多实用的接口和迭代器,使用起来的确可以方便不少。make_heap给出的接口中,前两个是任意类型的迭代器(当然,这里也可以直接传递数组的指针),不论是make_heap还是其他三个函数,这里的迭代器区间总是左闭右开的,这是个需要注意的地方。

接下来我们来介绍仿函数这里的实现。还是上面的例子,如何让上面剪子一个最小堆呢?

//仿函数结构:

struct Compare
{
bool operator()(int num1, int num2)
{
return num1 > num2;
}
};

// 建堆时,参数传递改为

make_heap(vec.begin(), vec.end() , Compare());  // 建小堆

注意,上面我写的是num1 > num2,这样建出来顶点是小堆。关于make_heap就说到这里。

2、push_heap与pop_heap

push表示的是向vector中插入一个元素,但这里它并不是直接插入元素,准确的说,它的功能只是做调整,在push_heap之前,首先需要调用vec.push_back(x),向vector尾部插入一个元素,然后在调用push_heap函数进行调整,使得整个树重新满足堆结构。

pop_heap与push_heap类似,同样没有直接改变vector中元素个数的能力。对于堆而言,pop要做的是将vector的第一个元素扔出去,为了不直接破坏树的结构,这里先调用pop_heap函数,将堆中的最大值或最小值放到vector的尾部,同时进行一次调整,使得堆结构依然成立,然后调用vec.pop+back()函数,将最后一个元素从vector中剔除。

这就是插入和删除的整个过程。

3、sort_heap

顾名思义,sort_heap就是进行堆排序的意思,对堆结构进行排序,得到的结果就是vector中的元素变得有序。这里,构建大堆,排序结果是升序的,构建小堆,得到的排序结果是降序的。

上面就是关于堆排序的基本算法,关于C++11新引入的两个函数,这里不做讨论。

关于STL中的堆结构,这里有几点还是需要注意的:

1、因为堆结构,是建立在vector上的结构,所以如果要进行堆排序,整个过程中至少一次建堆(make_heap)的过程。

2、当建堆完成之后,如果再向vector中插入元素,需要调用 push_heap(v1.begin(), v1.end())进行一次向上调整;如果从vector中Pop出一个元素,需要调用 pop_heap(v1.begin(), v1.end())进行一次向下调整。

如果没有调整,当调用 sort_heap(v1.begin(), v1.end())函数的过程中,会出现由于堆不合法引起的断言错误。

3、不可以让vector多次尾插,之后再多次向上调整,会造成堆混乱,排序时也会出现断言错误。当然,多次插入或删除之后,可以再次进行重新建堆,只不过消耗的时间代价会比较大。

堆结构实际应用

接下来,看一道面试题:

CVTE:统计公司员工最喜欢吃的前K种水果

有过上面的基础,我这里直接给出demo

#include   
#include   
#include   
#include   

struct Min  
{  
      bool operator()(pair p1, pair p2)  
      {  
            return p1.second > p2.second;  
      }  
};  
void HeapSort()  
{  
      vector v1 = { "苹果", "香蕉", "苹果"  
            , "苹果", "苹果", "香蕉"  
            , "苹果", "猕猴桃", "草莓" };  
      map fruit;  

      //用map统计次数  
      for (size_t i = 0; i < v1.size(); i++)   
            {   
                        fruit[v1[i]]++;   
            }   

            // 用heap排序   
            vector> vec;  
      map::iterator it = fruit.begin();  
      //while (it != fruit.end())  
      //{  
      //     vec.push_back(pair(it->first, it->second));  
      //     it++;  
      //}  
      vec.insert(vec.begin(), fruit.begin(), fruit.end());  
      make_heap(vec.begin(), vec.end(), Min());  
      sort_heap(vec.begin(), vec.end(), Min());  
      int K = 3;  
      for (size_t i = 0; (i < K) && (i < vec.size()); i++)   
            {   
                        cout << vec[i].first <<"--"<

堆排序是数据结构中一块很重要的内容,如果是在实际开发中,更加推荐的是熟悉STL中给出的算法,正如上文讲到的内容。如果是对于初学者,这里还是推荐对堆结构和算法的底层实现有一个更加深刻的认识,对于堆的调整算法,不可否认,是数据结构中较为重要的一部分。下一次,会对堆结构进行模拟实现,更加深入地了解底层结构。





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • STL
    STL
    +关注

    关注

    0

    文章

    86

    浏览量

    19151
  • C++语言
    +关注

    关注

    0

    文章

    147

    浏览量

    7594
  • STL算法
    +关注

    关注

    0

    文章

    6

    浏览量

    5518
  • 迭代器
    +关注

    关注

    0

    文章

    45

    浏览量

    4590

原文标题:浅析STL算法中的堆排序

文章出处:【微信号:TheAlgorithm,微信公众号:算法与数据结构】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    C++之STL算法(二)

    C++之STL算法(二)
    的头像 发表于 07-18 14:49 2709次阅读
    C++之<b class='flag-5'>STL</b><b class='flag-5'>算法</b>(二)

    c++之STL算法(三)

    c++之STL算法(三)
    的头像 发表于 07-18 15:00 2897次阅读
    c++之<b class='flag-5'>STL</b><b class='flag-5'>算法</b>(三)

    effective stl中文版下载pdf

    导读你已经熟悉了STL。你知道怎么建立容器,迭代它们的内容,添加删除元素和应用常见算法,比如find和sort。但你并不满足,你不能摆脱STL所提供的超过它们能带来的好处
    发表于 08-25 17:47 0次下载

    C++ STL的概念及举例

      本篇文章是作者本人使用STL 后的一些看法, 对於想要靠此文章学习STL, 是不可能的. 建议叁后面介绍的一些书入门.   STL的概念   在STL
    发表于 08-30 11:39 1616次阅读

    基于STL转换为X3D格式的研究

    通过对STL三角网格模型和X3D语法规范的分析与研究,根据X3D对三角形的相关定义和描述,提出了一种将STL三角网格模型转换为X3D格式的算法。该算法在实现将
    发表于 01-15 17:04 0次下载

    STL算法在GIS的应用

    使用STL 算法实现GIS 算法可以保证它的简洁和高效该文结合C++代码实例抽象出了地理算子的概念应用在GIS 算法当中通过定制适配器来消除地理算子和
    发表于 06-28 16:55 33次下载

    基于STL曲面网格重建算法

    快速获得完整拓扑关系且其存在大量冗余信息的缺点,制约了STL网格模型的进一步优化处理与应用.为此,需要针对STL网格模型进行网格重建.针对2维流形的STL三角形曲面网格模型,提出了一种快速的网格重建方法.主要利用删除在重建过程
    发表于 12-25 11:52 1次下载
    基于<b class='flag-5'>STL</b>曲面网格重建<b class='flag-5'>算法</b>

    C语言教程:STL-for-each算法

    C语言教程:STL-for-each算法(电源技术版面费5400)-文档为C语言教程:STL-for-each算法总结文档,是一份不错的参考资料,感兴趣的可以下载看看,,,,,,,,,
    发表于 09-17 12:42 3次下载
    C语言教程:<b class='flag-5'>STL</b>-for-each<b class='flag-5'>算法</b>

    STL的概述

    C++ STL 是一套功能强大的 C++ 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法,关于 STL ,下面通过一个系统框图来对其进行一个总结
    的头像 发表于 01-20 17:08 2137次阅读
    <b class='flag-5'>STL</b>的概述

    C++之STL的容器

    前面跟大家介绍过STL库,STL主要是由6大部分组成,其中第一个提到的就是容器,容器在介绍STL中小哥有简单的跟大家介绍过,今天稍微再详细介绍一下
    的头像 发表于 02-21 10:55 1998次阅读
    C++之<b class='flag-5'>STL</b>库<b class='flag-5'>中</b>的容器

    博途使用STL的MOVE指令

    现在,在 S7-1500 CPU 上可使用 STL 的 MOVE 指令进行编程。
    的头像 发表于 06-06 11:10 9539次阅读
    博途使用<b class='flag-5'>STL</b><b class='flag-5'>中</b>的MOVE指令

    如何显示STL程序的程序状态

    在表循环更新并显示程序的状态。执行 STL 程序后立即显示这些表格。并读取程序每一行的执行状态。显示内容取决于所用的 CPU(S7-300、S7-400 或 S7-1500)。
    的头像 发表于 08-23 10:31 1705次阅读
    如何显示<b class='flag-5'>STL</b>程序的程序状态<b class='flag-5'>呢</b>?

    如何在STL的EN/ENO机制仿真示例

    STL 程序块调用的程序块不提供 EN 和 ENO 参数。无论创建程序块时采用何种编程语言,都可通过状态字的 BR 位将错误语句传送到 STL 程序块
    的头像 发表于 09-01 09:45 1907次阅读

    C++STL容器的常见容器及基本操作

    一、什么是容器? 所谓容器,就是可以承载,包含元素的一个器件,它是STL六大组件之一,是容器、算法、迭代器中最重要也是最核心的一部分。 二、STL各大容器的结构与分类 2.1 顺序性
    的头像 发表于 11-10 11:23 1071次阅读
    C++<b class='flag-5'>中</b><b class='flag-5'>STL</b>容器<b class='flag-5'>中</b>的常见容器及基本操作

    STL内容介绍

    Library),是ANSI/ISO C++标准中最新的也是极具革命性的一部分。库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。为广大C++程序员们提供了一个可扩展的应用框架,高度体现了
    的头像 发表于 11-13 11:32 1827次阅读
    <b class='flag-5'>STL</b>内容介绍