上次用Java实现了最大堆的封装,这次就来写一下最小堆的实现吧


插入函数的思路:

向堆中插入元素有两种情况,一种是堆为空,那么就让插入值作为根节点即可;另一种是堆不为空,那么此时就要进行判断当前节点与其父节点的大小关系比较。此时仍有两种情况,一种是当前节点大于父节点,这样正是我们所希望的;另一种是当前节点的值小于父节点,那么就要将二者的值进行调换,然后记得更新当前节点为原来父节点的位置,而父节点的位置同样需要更新(循环正常终止的时候说明已经到了根节点,此时最小值必定为根节点)

 bool Insert(T data){
        if(currentPos==MaxSize){
            cout<<"Sorry , this heap is full!"<<endl;
            return false;
        }
        currentPos++;
        int targetPos=currentPos-1;
        heap[targetPos]=data;
        while(targetPos>0){
            int parentPos=(targetPos-1)/2;
            if(heap[parentPos]<heap[targetPos]){
                break;
            }else{
                heap[targetPos]=heap[parentPos];
                targetPos=parentPos;
            }
        }
        return true;
    }
    //存在的bug是对根节点的大小比较,因为有可能targetPos=0而退出,此时就缺少了一次比较

siftDown调整过程思路:

给定要进行调整的节点的下标,我们只需要让它和它的两个子节点中最小的那个比较即可(前提是当前节点不是叶子节点),需要注意的是要先保存当前节点的值,比较之后按大小调整顺序即可。

 void siftDown(int siftPos){

        int siftPosition=siftPos;
        T temp=heap[siftPosition];

        int minChildPos=2*siftPosition+1;
        while(minChildPos<currentPos){          //保证比较的条件成立
            if((minChildPos<currentPos-1)&&(heap[minChildPos]>heap[minChildPos+1])){
                minChildPos++;
            }
            if(temp<heap[minChildPos]){
                break;
            }else{
                heap[siftPosition]=heap[minChildPos];
                siftPosition=minChildPos;
                minChildPos=2*siftPosition+1;
            }
        }
        //作用:当要进行调换的位置不满足循环要求时,说明要进行调换的位置是叶子节点,那就不需要变换咯(这里也包括正常比较情况,可正常使用)
        heap[siftPosition]=temp;
 }

删除对顶元素

需要注意的是currentPos的大小要实时的进行更新,然后返回所删除的堆顶元素即可

 T& deleteTop(){
        if(currentPos<0){
            cout<<"Sorry ,this heap is empty!"<<endl;
        }
        T target=heap[0];
        heap[0]=heap[currentPos-1];
        currentPos--;
        siftDown(0);
        return target;
    }

下面是完整的C++关于最小堆的实现的代码

#include <iostream>

using namespace std;
template<class T>
class MinHeap{
    T *heap;
    int MaxSize;
    int currentPos;

public:
    MinHeap(int MS){
        heap=new T[MS];
        currentPos=0;
        MaxSize=MS;
    }

    bool Insert(T data){
        if(currentPos==MaxSize){
            cout<<"Sorry , this heap is full!"<<endl;
            return false;
        }
        currentPos++;
        int targetPos=currentPos-1;
        heap[targetPos]=data;
        while(targetPos>0){
            int parentPos=(targetPos-1)/2;
            if(heap[parentPos]<heap[targetPos]){
                break;
            }else{
                heap[targetPos]=heap[parentPos];
                targetPos=parentPos;
            }
        }
        return true;
    }

    void siftDown(int siftPos){

        int siftPosition=siftPos;
        T temp=heap[siftPosition];

        int minChildPos=2*siftPosition+1;
        while(minChildPos<currentPos){          //保证比较的条件成立
            if((minChildPos<currentPos-1)&&(heap[minChildPos]>heap[minChildPos+1])){
                minChildPos++;
            }
            if(temp<heap[minChildPos]){
                break;
            }else{
                heap[siftPosition]=heap[minChildPos];
                siftPosition=minChildPos;
                minChildPos=2*siftPosition+1;
            }
        }
        //作用:当要进行调换的位置不满足循环要求时,说明要进行调换的位置是叶子节点,那就不需要变换咯
        heap[siftPosition]=temp;

        ////////////////////////////////////////////

    }

    T& deleteTop(){
        if(currentPos<0){
            cout<<"Sorry ,this heap is empty!"<<endl;
        }
        T target=heap[0];
        heap[0]=heap[currentPos-1];
        currentPos--;
        siftDown(0);
        return target;
    }
};

int main()
{
    cout << "Hello world!" << endl;
    MinHeap<int> minHeap(7);
    minHeap.Insert(1);
    minHeap.Insert(2);
    minHeap.Insert(4);
    minHeap.Insert(3);
    minHeap.Insert(6);
    minHeap.Insert(7);
    minHeap.Insert(5);
    for(int i=1;i<=7;i++){
        cout<<minHeap.deleteTop()<<endl;
    }
    return 0;
}

程序运行结果如下


总结:

代码中存在一定得错误,出在 Insert函数中。个人认为需要对targetPos为0的特殊情况再加一层判断,估计就能解决。但是对正常添加元素还是能得到比较正常的结果的。

C++实现最小堆及插入,调整顺序,删除堆顶元素的操作的更多相关文章

  1. Java实现堆的封装,进行插入,调整,删除堆顶以完成堆排序实例

    简介 堆对于排序算法是一个比较常用的数据结构,下面我就使用Java语言来实现这一算法 首先,我们需要知道堆的数据结构的形式,其实就是一个特殊的二叉树.但是这个二叉树有一定的特点,除了是完全二叉树以外, ...

  2. 笔试算法题(46):简介 - 二叉堆 & 二项树 & 二项堆 & 斐波那契堆

    二叉堆(Binary Heap) 二叉堆是完全二叉树(或者近似完全二叉树):其满足堆的特性:父节点的值>=(<=)任何一个子节点的键值,并且每个左子树或者右子树都是一 个二叉堆(最小堆或者 ...

  3. PTA 最小堆插入元素和删除堆顶(无哨兵元素) (20分)

    PTA 最小堆插入元素和删除堆顶(无哨兵元素) (20分) 对于给定的最小堆(优先队列),分别实现插入元素和删除堆顶的函数. 函数接口定义: int insertIntoHeap(struct Hea ...

  4. 堆+建堆、插入、删除、排序+java实现

    package testpackage; import java.util.Arrays; public class Heap { //建立大顶堆 public static void buildMa ...

  5. Kafka集群优化篇-调整broker的堆内存(heap)案例实操

    Kafka集群优化篇-调整broker的堆内存(heap)案例实操 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.查看kafka集群的broker的堆内存使用情况 1>. ...

  6. 设顺序表中的数据元素递增有序,试着写一算法,将x插入到顺序表上的适当位置上,以保持该表的有序性。

    原创,转载请注明出处.https://www.cnblogs.com/yangf428/p/11254370.html 天勤例题[2-1]: 设顺序表va中的数据元素递增有序.试写一算法,将x插入到顺 ...

  7. 堆实战(动态数据流求top k大元素,动态数据流求中位数)

    动态数据集合中求top k大元素 第1大,第2大 ...第k大 k是这群体里最小的 所以要建立个小顶堆 只需要维护一个大小为k的小顶堆 即可 当来的元素(newCome)> 堆顶元素(small ...

  8. Java中数组的几个常用算法:插入算法,删除算法,冒泡排序算法

    前言: 在Java中我们常常会用数组,提到数组就不得不介绍数组中常用到的几个算法. 有插入算法,删除算法,冒泡排序算法等. 在学习这几个数组的算法前,我们先来了解一下关于数组一些基本知识. 数组的基本 ...

  9. 【bzoj5210】最大连通子块和 树链剖分+线段树+可删除堆维护树形动态dp

    题目描述 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...

随机推荐

  1. Linux系统格式化新磁盘并挂载分区

    Linux系统格式化新磁盘并挂载分区 在虚拟机的设置界面中,我们可以选择添加硬盘 添加好硬盘后,我们输入命令fdisk -l 看到有一个未经分区的硬盘 Fdisk命令编辑这个硬盘 输入n创建分区,p选 ...

  2. Hibernate异常之Integer转float(自动类型转换错误)

    错误代码: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Float at org.hiber ...

  3. Node.js 系统

    稳定性: 4 - API 冻结 提供一些基本的操作系统相关函数. 使用 require('os') 访问这个模块. os.tmpdir() 返回操作系统的默认临时文件夹 os.endianness() ...

  4. JavaScript的事件、DOM模型、事件流模型以及内置对象详解(三)

    JS中的事件 JS中的事件分类 1.鼠标事件: click/dbclick/mouseover/mouseout 2.HTML事件: onload/onunload/onsubmit/onresize ...

  5. UE4使用UMG接口操作界面

    原文链接:http://gad.qq.com/article/detail/7181131 本文首发腾讯GAD开发者平台,未经允许,不得转载 UE4的蓝图之强大让人欲罢不能,但是实际在项目的开发中,C ...

  6. XCode使用技巧

    XCode使用技巧 自动生成get.set方法 @property 用法 #import <Foundation/Foundation.h> @interface People : NSO ...

  7. Cocos2D-ObjC:在RPG游戏中混合Swift代码

    我之前写过一个RPG游戏<<熊猫之魂 SoulOfPanda>> 编译器使用的是SpriteBuilder,很好很强大!全部代码都由Objc完成,现在想尝试一下在其中混入Swi ...

  8. 远程拷贝、查看端口、vim常见快捷键、查找替换命令、grep命令、查看存储空间的命令、chkconfig命令、系统自动启动级别、主机名配置、IP地址配置、域名映射、防火墙设置

    2.1.远程拷贝 (将/export/servers/hadoop上的文件拷贝到bigdate@192.168.1.1:/export/servers/ ) scp –r /export/server ...

  9. Android 5.0新控件——TextInputLayout

    Android 5.0(M)新控件--TextInputLayout 介绍之前,先直观的看一下效果 TextInputLayout其实是一个容器,他继承自LinearLayout,该容器是作用于Tex ...

  10. 【SSH系列】---Hibernate的基本映射

    开篇前言       在前面的博文中,小编分别介绍了[SSH系列]-- hibernate基本原理&&入门demo,通过这篇博文,小伙伴们对hibernate已经有了基本的了解,以及h ...