C++实现最小堆及插入,调整顺序,删除堆顶元素的操作

简介: 上次用Java实现了最大堆的封装,这次就来写一下最小堆的实现吧插入函数的思路: 向堆中插入元素有两种情况,一种是堆为空,那么就让插入值作为根节点即可;另一种是堆不为空,那么此时就要进行判断当前节点与其父节点的大小关系比较。

上次用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的特殊情况再加一层判断,估计就能解决。但是对正常添加元素还是能得到比较正常的结果的。

目录
相关文章
|
2月前
|
搜索推荐 编译器 C语言
【C++核心】特殊的元素集合-数组与字符串详解
这篇文章详细讲解了C++中数组和字符串的基本概念、操作和应用,包括一维数组、二维数组的定义和使用,以及C风格字符串和C++字符串类的对比。
81 4
|
4月前
|
C++ 容器
C++中向量的操作vector
C++中向量的操作vector
|
6月前
|
存储 程序员 C++
C++堆内存分配
C++堆内存分配
57 2
|
5月前
|
算法 前端开发 Linux
【常用技巧】C++ STL容器操作:6种常用场景算法
STL在Linux C++中使用的非常普遍,掌握并合适的使用各种容器至关重要!
92 10
|
5月前
|
C++ iOS开发 开发者
C++一分钟之-文件输入输出(I/O)操作
【6月更文挑战第24天】C++的文件I/O涉及`ifstream`, `ofstream`和`fstream`类,用于读写操作。常见问题包括未检查文件打开状态、忘记关闭文件、写入模式覆盖文件及字符编码不匹配。避免这些问题的方法有:检查`is_open()`、显式关闭文件或使用RAII、选择适当打开模式(如追加`ios::app`)以及处理字符编码。示例代码展示了读文件和追加写入文件的实践。理解这些要点能帮助编写更健壮的代码。
62 2
|
5月前
|
C++
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
|
5月前
|
C++
C++数组中插入元素。
C++数组中插入元素。
|
4月前
|
安全 编译器 C++
【C++】string类的使用②(元素获取Element access)
```markdown 探索C++ `string`方法:`clear()`保持容量不变使字符串变空;`empty()`检查长度是否为0;C++11的`shrink_to_fit()`尝试减少容量。`operator[]`和`at()`安全访问元素,越界时`at()`抛异常。`back()`和`front()`分别访问首尾元素。了解这些,轻松操作字符串!💡 ```
|
6月前
|
C++
在C和C++中,指针的算术操作
在C和C++中,指针的算术操作
|
5月前
|
算法 C++ 容器
C++之vector容器操作(构造、赋值、扩容、插入、删除、交换、预留空间、遍历)
C++之vector容器操作(构造、赋值、扩容、插入、删除、交换、预留空间、遍历)
254 0