最小堆及其操作函数

前几天在做Kth Largest Element in an Array 时使用到了堆,通过那倒题目也了解到了堆的make_heap,push_heap,pop_heap操作,看了C++ reference中的讲解也明白了heap_sort是什么回事。于是想着自己实现以下这四个函数。

堆的定义:

  • 任意节点小于它的所有后裔,最小元在堆的根上(堆序性)。
  • 堆总是一棵完全树。
#include <iostream>
#include <string>
using namespace std;

//构造一个最小堆,最小堆是任何一个节点的左右子树中的值都比该节点值小
void downHelper(int *arr,int pos,int length);
void upHelper(int *arr,int pos);

//构造堆:
//只含有一个元素的节点一定是一个堆
//那么从数组中第(length-2)/2的节点开始逆序遍历数组,将每个节点都下调
void make_heap(int *arr,int length )
{
        for(int i=(length-2)/2;i>=0;i--)
        {
            downHelper(arr,i,length);
        }
}

//往堆中插入元素,它的含义是之前length-1个元素已经构成了堆,现在在最后添加一个元素
//重新构成堆,那么只需要对最后一个元素执行上调操作即可
void push_heap(int *arr,int length)
{
        upHelper(arr,length-1);
}

//从堆里面弹出元素,堆只能弹出堆顶的元素。
//对堆而言它的弹出操作是分两步进行的:
//1:将堆顶元素和对中最后一个元素互换
//2:对新的堆顶的元素执行下调操作
//这样执行弹出操作以后,堆的长度减少了1,并且弹出的元素被放在了最后
void pop_heap(int *arr,int length)
{
        swap(arr[0],arr[length-1]);
        downHelper(arr,0,length-1);
}

//上调操作,将pos位置的元素上调,这个操作在push_heap时会用到
//直到该个该节点的父节点的值比该节点值大才跳出循环
void upHelper(int *arr,int pos)
{
    while(pos!=0&&arr[pos]>arr[(pos-1)/2])
    {
        swap(arr[pos],arr[(pos-1)/2]);
        pos=(pos-1)/2;
    }
}

//下调操作,将pos位置的元素下调,直到堆的最后,当堆的长度为length时
//堆的最大下标是length-1
void downHelper(int *arr,int pos,int length)
{
    //如果左子节点存在并且左子节点的值大于当前节点
    while(pos*2+1<length&&arr[pos*2+1]>arr[pos])
    {
        //如果右子节点存在并且右子节点的值大于左子节点,那么将当前节点的值和右子节点交换
        if(pos*2+2<length&&arr[pos*2+2]>arr[pos+1])
        {
                swap(arr[pos],arr[pos*2+2]);
                pos=pos*2+2;
        }
        else//否则和左子节点交换
        {
                swap(arr[pos],arr[pos*2+1]);
                pos=pos*2+1;
        }
    }
}

//堆排序就是不断从堆中弹出一个元素,由于每次弹出的元素都是堆中最大的,
//并且每次弹出一个元素后堆的大小减少了1,堆顶的元素被放在了数组最后
//所以执行完弹出操作后数组就变成有序的了。
void sort_heap(int *arr,int length)
{
    make_heap(arr,length);
    for(int i=0;i<length-1;i++)
    {
        pop_heap(arr,length-i);
    }

}

int main()
{
    int a[]={10,20,30,5,15};
    make_heap(a,5);
    cout<<a[0]<<endl;
    pop_heap(a,5);
    cout<<a[0]<<endl;
    push_heap(a,5);
    cout<<a[0]<<endl;
    sort_heap(a,5);
    cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<" "<<a[3]<<" "<<a[4]<<endl;
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-27 17:54:54

最小堆及其操作函数的相关文章

[数据结构]最小堆的类模板实现

堆数据结构是一种数组对象,它可以被视为一科完全二叉树结构. 它的特点是父节点的值大于(小于)两个子节点的值(分别称为最大堆和最小堆).它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等. 1.根结点若有子树,则子树一定也是堆. 2.根结点一定大于(或小于)子结点. 因为要求堆必须是完全二叉树,所以可以用线性的数据结构,比如数组,来实现堆. 利用数组实现,则对于长为N的堆中的元素从0到N-1排列,有: i的父结点:Parent(i)=(i+1)/2-1 i的左叶子:Left(i)=(

Q窗口操作函数(窗口最大化,全屏,隐藏最大化最小化按钮)

//Qt主窗口没有最小化,最大化按钮且最大化显示  int main(int argc, char *argv[]) { QApplication a(argc, argv); TestQtForWinCE w; w.setWindowFlags(w.windowFlags()& ~Qt::WindowMaximizeButtonHint& ~Qt::WindowMinimizeButtonHint); w.showMaximized(); return a.exec(); } 这里的&q

通用的最小堆(最大堆)D-ary Heap

听说有一种最小(大)堆,不限于是完全二叉树,而是完全D叉树,名为D-ary Heap(http://en.wikipedia.org/wiki/D-ary_heap).D可以是1,2,3,4,100,对于优先队列该有的功能都没有问题. 动手写一个D-ary Heap,应该不难.简单起见,不考虑像STL一样通过template传入Comp类,下面的实现要求T类型重载了operator <和operator >. template<class T> class DaryHeap { s

最小堆的建立 插入 与删除

堆是完全二叉树,完全二叉树最大的特点就是 把数据储存在数组里 通过父子结点的关系来做  不用实际建树  parent=leftchild/2: leftchild=2*parent  右就加1这儿指的是序号关系,储存的时候注意是利用树的逻辑图 从上到下 从左到右编号12345..... 建堆:实际是把数据先放入数组(注意下标从1开始),对应逻辑图,写调整代码,我的基本思路是从数组末尾开始,对应元素与其父节点比较,满足条件就换值,并且对被换的调用调整函数(要单独写个调整函数)因为被换的一个是可能不

Jcompress: 一款基于huffman编码和最小堆的压缩、解压缩小程序

前言 最近基于huffman编码和最小堆排序算法实现了一个压缩.解压缩的小程序.其源代码已经上传到github上面: Jcompress下载地址 .在本人的github上面有一个叫Utility的repository,该分类下面有一个名为Jcompress的目录便是本文所述的压缩.解压缩小程序的源代码.后续会在Utility下面增加其他一些实用的小程序,比如基于socket的文件断点下载小程序等等.如果你读了此文觉得还不错,不防给笔者的github点个star, 哈哈.在正式介绍Jcompres

hdu 4006 The kth great number (优先队列+STB+最小堆)

The kth great number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 6637    Accepted Submission(s): 2671 Problem Description Xiao Ming and Xiao Bao are playing a simple Numbers game. In a roun

优先队列及最小堆最大堆

为什么优先队列里默认是堆(heap)实现,默认是优先级高的出队,定义结构体重载函数为什么要按照从小到大排序?原来是自己对优先队列还不太了解: 1 堆 1.1 简介 n个关键字序列Kl,K2,-,Kn称为(Heap),当且仅当该序列满足如下性质(简称为堆性质): (1)ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n),当然,这是小根堆,大根堆则换成>=号.//k(i)相当于二叉树的非叶结点,K(2i)则是左孩子,k(2i+1)是右孩子 若将此序列所存储的向量R[1..n]看做是一

最大堆(最小堆)

最大堆是一种很有用的数据结构,它是一颗完全二叉树,并且如果一个节点有儿子节点,其关键字都不小于其儿子节点的关键字.(最小树反之:节点值不大于儿子节点的完全二叉树.) 最大堆使用的一个典型的地方就是找出无序数字中,最大的一个数字.比如100亿整数中找出最小的前100个数字,典型的解决方案之一就是:先去处前边一百个值,创建一个最大堆,然后顺序读入的剩下的每个值,如果值小于根节点值,则删除根节点,把这个值插入,重建最大堆.重复这过程.最后就得到了最小的前100个数字(如果找前100个最大的值,就建立一

优先队列的实现(最小堆)

使用最小堆实现优先队列 定义上浮函数和下浮函数,对每一次加入的新节点,重新维护最小堆 代码: public class PriorityMinQueue { private int[] arr; private int size; /** * 返回优先队列的大小 * * @return */ public int Size() { return size; } public PriorityMinQueue() { this(20); } /** * 初始化优先队列 * * @param cap