Code前端首页关于Code前端联系我们

STL算法之堆排序:底层是数组,又保持二叉树特性

terry 2年前 (2023-09-27) 阅读数 90 #数据结构与算法
STL堆排序算法:底层是序号,同时保留了二叉树堆结构的特点。堆栈的较低层使用数组实现,但保留了二叉树的性质。堆有两种类型:最大数据堆和最小数据堆。以最终堆为例,根堆比左右两个孩子拥有更大的根,并且所有孩子都被一次性取出。由于堆的底层是数组结构,所以我们从下一个节点开始,按顺序走到最后一个节点。节点顺序为0~N-1。结构如下图:

STL算法之堆排序:底层是数组,又保持二叉树特性

上图中,紫色代表数组中元素的踪迹。可以看出,每个节点的值都大于其左右子节点。左右儿童没有尺寸要求。连通性并不指定同一棵树中节点之间的关系范围。这是最高级别。同时,这里可以注意的是,如果是一个大堆,那么底座一定是树中最大的。同样,如果是一个小堆,那么根一定是树中最小的节点。

分类方案中堆结构较低,但STL中没有直接提供堆结构。而是将堆相关的算法写在算法中。我不会在这里过多地介绍捆绑包的模拟和实现。今天我要讲的是如何使用STL中提供的堆算法。

堆算法

在STL中,提供了多种堆算法。

★make_heap

★push_heap

★pop_heap

★sort_heap

这里给出第一个使用算法的例子‽♿♿上面的代码使用了第一个数组建筑 获取向量,然后在vec vec上构建堆,提取构建的向量的第一个元素,对其进行排序,然后进行堆排序,最后打印结果。输出结果如下:

STL算法之堆排序:底层是数组,又保持二叉树特性

读完堆算法基本使用。现在,让我们看看这些界面是如何在STL中呈现的。

1。 make_heap

STL算法之堆排序:底层是数组,又保持二叉树特性

前面说过,分为主堆和小堆。我们在创建堆的时候需要指定堆,但是在前面的例子中我们没有指定堆的大小。 STL规定,如果不指定,默认是大栈结构。从上面两组make_heap接口可以看出,第一组是默认的,没有提供定义堆大小的接口,而这里实现了第二组。我们可以在函子的结构体中实现这里传递的参数。

对于给定的例子,我们现在可以解释另一个问题,为什么我们在进行堆排序时需要先构建一个向量?因为堆的主要实现是数组的形式,而向量是对堆数组的高层封装,所以这些库中的容器集提供了很多接口和迭代器,使用起来方便很多。 make_heap提供的接口中,前两个是所有类型的迭代器(当然这里也可以直接传递数组指针)。无论是make_heap还是其他三个函数,这里的服务器空间总是左边关闭,右边打开。 ,这是需要注意的事情。

接下来我们在这里介绍函子的实现。还是上面的例子,我们如何让顶部成为最小的一堆呢?

<span style="font-family:'楷体', '楷体_GB2312', SimKai;font-size:18px;">//仿函数结构:</span><span style="font-family:sans-serif;"><br><br>struct Compare<br>{<br><span style="line-height:0px;"></span><span style="line-height:0px;"></span>   bool operator()(int num1, int num2)<br>               {<br>            return num1 > num2;<br>    }<span style="line-height:0px;"></span><span style="line-height:0px;"></span><br>};</span><br>

//构建堆栈时,参数shift改为

<span style="font-size:18px;font-family:'楷体', '楷体_GB2312', SimKai;">make_heap(vec.begin(), vec.end() , Compare());   // 建小堆<br></span

<span style="font-size:18px;font-family:'楷体', '楷体_GB2312', SimKai;">make_heap(vec.begin(), vec.end() , Compare());   // 建小堆<br></span

注意,我上面写的是num1 > num2,所以这样构建的顶点是小堆栈。这是针对 make_heap 的。

2。 push_heap 和 pop_heap

push 的意思是向向量中插入一个元素,但这里不是直接插入元素。事实上,他的工作只是进行调整。在push_heap之前,需要先调用vec .push_back(x),在向量的末尾添加一个元素,然后调用push_heap函数进行调整,使树再次整体符合堆结构。

pop_heap 与push_heap 相同。它无法直接更改向量中元素的数量。对于堆来说,pop 所做的就是丢弃向量的第一个元素。为了避免直接破坏树结构,首先调用pop_heap函数将堆中的最大值或最小值放在向量的末尾。同时,进行调整,使堆结构仍然可用,然后调用 vec.pop+back() 函数从向量中删除最后一个元素。

这就是添加和删除的整个过程。

3。 sort_heap

顾名思义,sort_heap就是排序的意思。对堆栈结构进行排序会导致向量的元素被排序。这里,当形成大堆时,排序结果按升序排列,而当形成小堆时,排序结果按降序排列。

以上就是bundle类型的基本算法。关于C++11中新引入的两个函数,这里不再讨论。

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

1。因为堆系统是一个基于向量的系统,所以如果要做堆排序,整个过程中必须至少构建一次堆(make_heap)。

2。构建完成后,如果再次向向量中插入元素,则需要调用push_heap(v1.begin(), v1.end())进行向上调整;如果从向量中弹出一个元素,则需要调用 pop_heap(v1.begin(), v1.end()) 进行向下调整。

如果不修正,调用sort_heap(v1.begin(), v1.end())函数时,会因为非法堆而出现断言错误。

3。你不能允许尾部向量被多次加载,然后生成多次,这会在排序时造成混乱和优化错误。当然,重复插入或删除后,可以重建堆,但时间成本会很高。

堆栈结构的实际应用

接下来看调查题:

CVTE:统计公司员工想吃的高K水果

如果你具备了以上基础,我就给出现场演示在这里

#include <algorithm>   
#include <map>   
#include <string>   
#include <vector>   

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

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

            // 用heap排序   
            vector<pair<string, int>> vec;   
            map<string, int>::iterator it = fruit.begin();   
            //while (it != fruit.end())   
            //{   
            //         vec.push_back(pair<string, int>(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 <<"--"<<vec[i].second<< endl;   
            }   
}   
int main()   
{   
            HeapSort();   
            system("pause");   
            return 0;   
}

堆排序是数据结构中非常重要的一部分。在实际开发中,最好了解STL中给出的算法,如上所述。如果你刚刚入门,建议对系统和算法的基本实现有更深入的了解。堆校正算法无疑是数据结构的重要组成部分。接下来我们将模拟桩结构并更深入地了解底层结构。

来自:“木慧”博客

链接:http://muhuizz.blog.51cto.com/11321490/1879003

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门