数据结构c/c++--------------------堆

原理

堆是一个用数组表示的完全二叉树,如下图:
在这里插入图片描述
结构体定义
在结构体中定义了一个指针动态分配一个空间表示数组,size方便我们知道当前数组元素的个数,capacity方便我们判断堆是否满了

#define MAX 1024	// 最大容量

typedef struct _Heap 
{
	int* arr;		
	int size;		// 当前个数
	int capacity;	// 容量
}Heap;

代码实现

建堆

我们可以在已有的数组进行调整,从而实现堆的建立
在初始化中我们将堆,已有的数组,已有数组的大小传进来,对堆的数组进行动态分配内存,同时通过bulidHeap函数对数组进行调整

bool initHeap(Heap& h, int* arr, int len)
{
	if (!arr) return false;

	int capacity = len > MAX ? len : MAX;

	h.arr = new int[capacity];
	if (!h.arr) return false;

	h.capacity = capacity;
	h.size = 0;

	if (len > 0)
	{
		h.size = len;
		memcpy(h.arr, arr, sizeof(int) * len);
		bulidHeap(h);

	}

	return true;
}
static void bulidHeap(Heap& h)
{
	for (int i = h.size / 2  - 1; i >= 0; i--)
	{
		adjustDown(h, i);
	}
}

我们采取向下调整的方式,我们从最后一个节点的父节点开始进行向下调整,如果他的左右孩子大于他,那么我们进行交换,交换完成后继续判断该节点是否有左右孩子,再次进行调整。
从最后一节点的父节点依次往前遍历堆的所有节点,进行向下调整,从而建立最大堆(可以改变一部分代码 建立最小堆)

static void adjustDown(Heap& h, int index)
{
	int cur = h.arr[index];	// 记录当前数据
	int child, parent;

	for (parent = index; (parent * 2 + 1) < h.size; parent = child)
	{
		child = parent * 2 + 1;	// 节点的做孩子的数组下标

		// 如果存在有孩子 取大的那个
		if ((child + 1) < h.size && h.arr[child] < h.arr[child + 1])
		{
			child = child + 1;
		}

		if (cur >= h.arr[child])
		{
			break;
		}
		else
		{
			h.arr[parent] = h.arr[child];
			h.arr[child] = cur;
		}
	}
}

插入

我们在插入时,先将要插入的数据放到堆的最后位置,然后对该元素进行向上调整,如果他的父节点小于他进行交换,知道父节点不小于他或者成为堆顶元素。

这里的插入同样可以作为初始化堆的方式,将原数组中的数据一个一个插入到堆中。

static void adjustUp(Heap& h, int index)
{
	int cur = h.arr[index];
	int parent, child;

	child = index;

	while (child >= 0)
	{
		parent = (child - 1) / 2;
		if (parent >= 0)
		{
			if (h.arr[child] <= h.arr[parent])
			{
				break;
			}
			else
			{
				h.arr[child] = h.arr[parent];
				h.arr[parent] = cur;

				child = parent;
			}
		}
		else
		{
			break;
		}
	}

}

// 插入
bool insertHeap(Heap& h, int val)
{
	if (h.size == h.capacity)
	{
		cout << "堆满" << endl;
		return false;
	}

	h.arr[h.size++] = val;

	adjustUp(h, h.size - 1);

	return true;
}

删除堆顶元素

我们将堆顶元素和堆最后一个元素进行交换,然后对其进行向下调整。

// 删除堆顶元素
bool deleteHeap(Heap& h)
{
	if (h.size == 0)
	{
		cout << "堆空" << endl;
		return false;
	}

	h.arr[0] = h.arr[h.size - 1];
	h.size--;

	adjustDown(h, 0);
	return true;
}

堆排序

将堆顶元素和最后一个元素进行交换,然后排除最后一个元素,对堆顶元素进行向下调整。循环该过程,直至排除到只剩一个元素。
在这里插描述

bool sortHeap(Heap& h)
{
	if (h.size == 0)
	{
		cout << "堆空" << endl;
		return false;
	}

	while (h.size > 0)
	{
		int tmp = h.arr[0];

		h.arr[0] = h.arr[h.size-1];
		h.arr[h.size - 1] = tmp;
		h.size--;
		adjustDown(h, 0);
	}
	return true;
}

完整代码

#include <iostream>
using namespace std;

#define MAX 1024	// 最大容量

typedef struct _Heap 
{
	int* arr;		
	int size;		// 当前个数
	int capacity;	// 容量
}Heap;

static void adjustDown(Heap& h, int index)
{
	int cur = h.arr[index];	// 记录当前数据
	int child, parent;

	for (parent = index; (parent * 2 + 1) < h.size; parent = child)
	{
		child = parent * 2 + 1;	// 节点的做孩子的数组下标

		// 如果存在有孩子 取大的那个
		if ((child + 1) < h.size && h.arr[child] < h.arr[child + 1])
		{
			child = child + 1;
		}

		if (cur >= h.arr[child])
		{
			break;
		}
		else
		{
			h.arr[parent] = h.arr[child];
			h.arr[child] = cur;
		}
	}
}

static void bulidHeap(Heap& h)
{
	for (int i = h.size / 2  - 1; i >= 0; i--)
	{
		adjustDown(h, i);
	}
}

bool initHeap(Heap& h, int* arr, int len)
{
	if (!arr) return false;

	int capacity = len > MAX ? len : MAX;

	h.arr = new int[capacity];
	if (!h.arr) return false;

	h.capacity = capacity;
	h.size = 0;

	if (len > 0)
	{
		h.size = len;
		memcpy(h.arr, arr, sizeof(int) * len);
		bulidHeap(h);

	}

	return true;
}

static void adjustUp(Heap& h, int index)
{
	int cur = h.arr[index];
	int parent, child;

	child = index;

	while (child >= 0)
	{
		parent = (child - 1) / 2;
		if (parent >= 0)
		{
			if (h.arr[child] <= h.arr[parent])
			{
				break;
			}
			else
			{
				h.arr[child] = h.arr[parent];
				h.arr[parent] = cur;

				child = parent;
			}
		}
		else
		{
			break;
		}
	}

}

// 插入
bool insertHeap(Heap& h, int val)
{
	if (h.size == h.capacity)
	{
		cout << "堆满" << endl;
		return false;
	}

	h.arr[h.size++] = val;

	adjustUp(h, h.size - 1);

	return true;
}

// 删除堆顶元素
bool deleteHeap(Heap& h)
{
	if (h.size == 0)
	{
		cout << "堆空" << endl;
		return false;
	}

	h.arr[0] = h.arr[h.size - 1];
	h.size--;

	adjustDown(h, 0);
	return true;
}

// 堆排序
bool sortHeap(Heap& h)
{
	if (h.size == 0)
	{
		cout << "堆空" << endl;
		return false;
	}

	while (h.size > 0)
	{
		int tmp = h.arr[0];

		h.arr[0] = h.arr[h.size-1];
		h.arr[h.size - 1] = tmp;
		h.size--;
		adjustDown(h, 0);
	}
	return true;
}

int main(void)
{
	Heap h;
	
	int arr[] = { 1,4,2,5,1,2,5,7,4,3 };
	int len = sizeof(arr) / sizeof(arr[0]);
	
	initHeap(h, arr, len);
	for (int i = 0; i < len; i++)
	{
		cout << h.arr[i] << " ";
	}
	cout << endl;

	cout << "插入6" << endl;
	insertHeap(h, 6);
	for (int i = 0; i < h.size; i++)
	{
		cout << h.arr[i] << " ";
	}
	cout << endl;

	cout << "删除堆顶元素" << endl;
	deleteHeap(h);
	for (int i = 0; i < h.size; i++)
	{
		cout << h.arr[i] << " ";
	}
	cout << endl;

	cout << "堆排序之后" << endl;
	sortHeap(h);
	for (int i = 0; i < len; i++)
	{
		cout << h.arr[i] << " ";
	}
	cout << endl;

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值