最小堆C++实现

    技术2024-08-17  65

    最小堆是指在树中,存在一个结点而且该结点有儿子结点,该结点的data域值都小于其儿子结点的data域值,并且它是一个完全二叉树(不是满二叉树)。

    这里使用静态数组存储完全二叉树,对于完全二叉树采用顺序存储表示,那么对于任意一个下标为i(1 ≤ i ≤ n)的结点:

    父结点为:i / 2(i ≠ 1),若i = 1,则i是根节点。左子结点:2i(2i ≤ n), 若不满足则无左子结点。右子结点:2i + 1(2i + 1 ≤ n),若不满足则无右子结点。

     最小堆的定义:

    class MinHeap { public: MinHeap(int size); ~MinHeap(); void Insert(int number);//最小堆插入元素 void Delete();//最小堆删除元素 void swap(int& a, int& b) { int temp = a; a = b; b = temp; }//交换元素 int GetNum() { return count - 1; }//获取最小堆元素个数 void printHeap();//打印堆元素 friend void sort(MinHeap& minheap,int* res,int n);//最小堆排序,res是排序后的数组指针 private: int* p;//数组指针 int count;//最小堆元素数量 int maxsize;//最小堆的最大元素数量 };

    最小堆的插入:

    最小堆的插入操作可以看成是“结点上浮”。当我们在向最小堆中插入一个结点我们必须满足完全二叉树的标准,那么被插入结点的位置的是固定的。而且要满足父结点关键字值不小于子结点关键字值,那么我们就需要去移动父结点和子结点的相互位置关系。

    //最小堆插入元素 void MinHeap::Insert(int number) { if (count > maxsize) { cout << "内存不足,请重新分配空间" << endl; return; } //插入元素 p[count] = number; //获取当前下标 int curCount = count; //节点上浮 while (curCount/2) { //如果子节点比父节点小,交换节点值,即上浮 if (p[curCount] < p[curCount / 2]) swap(p[curCount], p[curCount / 2]); //更新当前结点坐标值 curCount /= 2; } count++; }

    最小堆的删除:

    最大堆的删除操作,即从堆的根结点删除元素,同时在将最小堆的最后一个元素移动到根节点处,进行“下降”操作,使其重新平衡成为最小堆。

    每次下降操作父节点都需要分对左子节点与右子节点进行判断

    //最小堆删除元素 void MinHeap::Delete() { int curCount = 1; int num = GetNum();//获取最小堆元素总数 p[curCount] = p[num];//删除根结点元素,并将其替换为尾部元素 p[num] = 0; //下降操作 //当子节点存在时 while (2 * curCount <= num - 1) { //如果左子节点存在且父节点大于左子节点 if (p[curCount] > p[2 * curCount]) swap(p[curCount], p[2 * curCount]); //如果右子节点存在且父节点大于右子节点 if(2 * curCount + 1 <= num - 1 && p[curCount] > p[2 * curCount+1]) swap(p[curCount], p[2 * curCount + 1]); //更新当前结点坐标值 curCount *= 2; } count--; }

    最小堆的排序:

    原理和上面的删除是一样的,你可以认为进行了n次删除就能的到排序结果,不过在删除的根结点的时,把每次得到的根结点值插入到了另外的数组中了,最后返回这个另外的数组

    //最小堆排序 void sort(MinHeap& minheap,int res[],int n) { //res = new int[minheap.count - 1]; int index = minheap.count; for (int i = 0; i < n; i++) { int curCount = 1; int num = index - 1;//获取最小堆元素总数 res[i] = minheap.p[curCount]; minheap.p[curCount] = minheap.p[num];//删除根结点元素,并将其替换为尾部元素 //下降操作,当子节点存在时 while (2 * curCount <= num - 1) { //如果左子节点存在且父节点大于左子节点 if (minheap.p[curCount] > minheap.p[2 * curCount]) swap(minheap.p[curCount], minheap.p[2 * curCount]); //如果右子节点存在且父节点大于右子节点 if (2 * curCount + 1 <= num - 1 && minheap.p[curCount] > minheap.p[2 * curCount + 1]) swap(minheap.p[curCount], minheap.p[2 * curCount + 1]); //更新当前结点坐标值 curCount *= 2; } index--; } }

    全部代码:

    minheap.h

    #pragma once #ifndef MINHEAP_H #define MINHEAP_H #include<iostream> using std::cout; using std::cin; using std::endl; class MinHeap { public: MinHeap(int size); ~MinHeap(); void Insert(int number);//最小堆插入元素 void Delete();//最小堆删除元素 void swap(int& a, int& b) { int temp = a; a = b; b = temp; }//交换元素 int GetNum() { return count - 1; }//获取最小堆元素个数 void printHeap();//打印堆元素 friend void sort(MinHeap& minheap,int* res,int n);//最小堆排序,res是排序后的数组指针 private: int* p;//数组指针 int count;//最小堆元素数量 int maxsize;//最小堆的最大元素数量 }; MinHeap::MinHeap(int size) { maxsize = size; p = new int[maxsize + 1]; if (p == nullptr) { cout << "内存分配失败!" << endl; exit(-1); } count = 1; } MinHeap::~MinHeap() { if (p != nullptr) delete[] p; } //最小堆插入元素 void MinHeap::Insert(int number) { if (count > maxsize) { cout << "内存不足,请重新分配空间" << endl; return; } //插入元素 p[count] = number; //获取当前下标 int curCount = count; //节点上浮 while (curCount/2) { //如果子节点比父节点小,交换节点值,即上浮 if (p[curCount] < p[curCount / 2]) swap(p[curCount], p[curCount / 2]); //更新当前结点坐标值 curCount /= 2; } count++; } //最小堆删除元素 void MinHeap::Delete() { int curCount = 1; int num = GetNum();//获取最小堆元素总数 p[curCount] = p[num];//删除根结点元素,并将其替换为尾部元素 p[num] = 0; //下降操作 //当子节点存在时 while (2 * curCount <= num - 1) { //如果左子节点存在且父节点大于左子节点 if (p[curCount] > p[2 * curCount]) swap(p[curCount], p[2 * curCount]); //如果右子节点存在且父节点大于右子节点 if(2 * curCount + 1 <= num - 1 && p[curCount] > p[2 * curCount+1]) swap(p[curCount], p[2 * curCount + 1]); //更新当前结点坐标值 curCount *= 2; } count--; } void MinHeap::printHeap() { cout << "开始打印:"; for (int i = 1; i < count; ++i) cout << p[i] << " "; cout << endl; } //最小堆排序 void sort(MinHeap& minheap,int res[],int n) { //res = new int[minheap.count - 1]; int index = minheap.count; for (int i = 0; i < n; i++) { int curCount = 1; int num = index - 1;//获取最小堆元素总数 res[i] = minheap.p[curCount]; minheap.p[curCount] = minheap.p[num];//删除根结点元素,并将其替换为尾部元素 //下降操作,当子节点存在时 while (2 * curCount <= num - 1) { //如果左子节点存在且父节点大于左子节点 if (minheap.p[curCount] > minheap.p[2 * curCount]) swap(minheap.p[curCount], minheap.p[2 * curCount]); //如果右子节点存在且父节点大于右子节点 if (2 * curCount + 1 <= num - 1 && minheap.p[curCount] > minheap.p[2 * curCount + 1]) swap(minheap.p[curCount], minheap.p[2 * curCount + 1]); //更新当前结点坐标值 curCount *= 2; } index--; } } #endif // !MINHEAP_H

    main.cpp

    // MinHeap.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> using namespace std; #include"minheap.h" int main() { MinHeap myheap(256); int sample[] = { 12,11,23,2,4,5,3,8,9,10 }; for (int i = 0; i < sizeof(sample)/sizeof(int); i++) myheap.Insert(sample[i]); cout << "最小堆元素总数:"<<myheap.GetNum() << endl; myheap.printHeap(); myheap.Delete(); cout << "删除根节点!" << endl; myheap.printHeap(); //for (int i = 0; i < 8; i++) // myheap.Delete(); //myheap.printHeap(); int res[9] = { 0 }; sort(myheap, res, 9); cout << sizeof(res) / sizeof(int) << endl; for (int i = 0; i < sizeof(res)/sizeof(int); i++) cout << res[i] << " "; }

     

    Processed: 0.011, SQL: 9