最小堆C++实现

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

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

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

最小堆C++实现_第1张图片

 最小堆的定义:

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
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 
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 << "最小堆元素总数:"<

 

你可能感兴趣的:(数据结构,c++)