原理
堆是一个用数组表示的完全二叉树,如下图:
结构体定义
在结构体中定义了一个指针动态分配一个空间表示数组,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;
}