赞
踩
数据结构——顺序表的C语言代码实现
数据结构——八种链表的C语言代码实现
数据结构——栈的C语言代码实现
数据结构——队列的C语言代码实现
数据结构——堆的C语言代码实现
本文主要学习如何实现最大队和最小堆的创建、插入、删除等。
堆是考虑特权的数据结构,被称作优先队列
在前面学习队列时,我们曾举例:在银行中排队处理业务,来解释队列“先进先出”的特点。
而在学习堆时,我们可以联想打印店排队:某一个用户需要打印数百页的资料,而排在他后面的顾客只需打印一两页的试题,那么此时店主和前客户一般都会同意优先处理后客户的需求。
堆是特殊的队列,最常用结构是完全二叉树又因为完全二叉树必的节点规律性极强,故常用数组实现堆的存储。
对于下标为i的节点,其父节点下标为i/2,其左右孩子节点下标为2i、2I+1
主要实现创建、插入、删除和打印。最大堆与最小堆的接口函数一致。
注意在用数组存储堆时,我们使用的数组下标是从1开始的,空余的下标0用于存放规定的最大值或者最小值,便于插入时进行操作。
代码如下:
#define _CRT_SECURE_NO_WARNINGS 1 #define MAX 10000000 #include<stdio.h> #include<stdlib.h> #include<stdbool.h> typedef int DataType; typedef struct Heap { DataType* arr; int size; int capacity; }*Heap; //创建堆 Heap CreateHeap(int maxsize); //检测是否已满 bool CheckFull(Heap h); //检测是否已空 bool CheckEmpty(Heap h); //插入 void Insert(Heap h, DataType x); //删除 DataType Delete(Heap h); //打印 void Print(Heap h);
最大堆与最小堆的接口函数实现大同小异。重点注意实现插入与删除时。使用的过滤方法!
因为从下标1开始存储,所以申请空间时,要申请maxsize+1个空间
代码如下:
//创建堆
Heap CreateHeap(int maxsize)
{
Heap h = (Heap)malloc(sizeof(struct Heap));
h->arr = (DataType*)malloc(sizeof(DataType) * (maxsize + 1));
h->capacity = maxsize;
h->size = 0;
//数组从下标1开始存放数据,arr[0]存放最大值,
//便于插入时进行过滤操作
h->arr[0] = MAX;
return h;
}
代码如下:
//检测是否已满
bool CheckFull(Heap h)
{
return h->size == h->capacity;
}
代码如下:
//检测是否已空
bool CheckEmpty(Heap h)
{
return h->size == 0;
}
主要思路:
1、先判断数组是否已满
2、将数组的size加一赋值为i,然后从数组最后一个下标i开始,依次用父节点(下标为2/i)与插入的数X比较大小
3、在最大堆中,如果父节点小于X,则将父节点下移到孩子节点,然后将i迭代,继续上述比较;在最小堆中,如果父节点大于X,则将父节点移到孩子节点,然后将i迭代,继续上述操作;
4、最终当判断条件结果为假时,X就找到了要插入的位置下标。
代码如下:
//最大堆插入 void Insert(Heap h, DataType x) { if (CheckFull(h)) { printf("最大堆已满!\n"); return; } else { //最大堆插入元素后,最后的数据位置下标 int i = ++h->size; //从最后一个位置向上过滤父节点 //如果X大于父节点,则父节点下移 for (; h->arr[i / 2] < x; i /= 2) { h->arr[i] = h->arr[i / 2]; } //当X小于父节点,此时i就是要插入的位置 h->arr[i] = x; } }
//最小堆的插入 void Insert(Heap h, DataType x) { if (CheckFull(h)) { printf("\n"); return; } else { int i = ++h->size; for (; h->arr[i / 2] > x; i /= 2) { h->arr[i] = h->arr[i / 2]; } h->arr[i] = x; } }
主要思路:
1、先判断数组是否已空;
2、取出最大值或者最小值(下标为1的数组元素);
3、然后删除最后一个元素的空间,将原数组的最后一个元素num从上到下,与兄弟节点中较大的进行比较,找到要插入的位置;
即先从下标为1开始,它的两个孩子下标分别为2、3,先找到较大的孩子节点。假设是下标为2,用下标为2的元素与num相比。在最大堆中,如果num小,则将下标为1的元素赋值为下表为2的元素(节点上移),然后迭代继续比较,直到num较大,此时的父节点就是X要插入的位置。而在最小堆中,就是比较的结果恰恰相反。
代码如下:
//最大堆删除 DataType Delete(Heap h) { if (CheckEmpty(h)) { printf("最大堆已空!\n"); exit(-1); } else { //取出最大元素 int Max = h->arr[1]; //用最后一个节点元素从上向下过滤 int num = h->arr[h->size--]; int parent, child; for (parent = 1; 2 * parent <= h->size; parent = child) { child = parent * 2; //找到两个孩子中较大的一个 if (child != h->size && h->arr[child + 1] > h->arr[child]) child += 1; //最后一个节点大于孩子节点,则找到了正确位置 //最后一个节点插入到父节点 if (num >= h->arr[child]) break; else h->arr[parent] = h->arr[child]; } h->arr[parent] = num; return Max; } }
//最小堆删除 DataType Delete(Heap h) { if (CheckEmpty(h)) { printf("ѿ!\n"); exit(-1); } else { DataType min = h->arr[1]; DataType num = h->arr[h->size--]; int parent, child; for (parent = 1; parent * 2 <= h->size; parent = child) { child = parent * 2; if (child != h->size && h->arr[child] > h->arr[child + 1]) child += 1; if (h->arr[child] >= num) break; else h->arr[parent] = h->arr[child]; } h->arr[parent] = num; return min; } }
代买如下:
//打印
void Print(Heap h)
{
int i = 1;
for (; i <= h->size; i++)
{
printf("%d ", h->arr[i]);
}
}
最大堆:
#include"MaxHeap.h" int main() { int maxsize = 100; Heap h = CreateMaxHeap(maxsize); int input = 0; int count = 0; while ((scanf("%d", &input) == 1)&&count<=maxsize) { Insert(h, input); count++; } printf("最大堆为:\n"); Print(h); int max = Delete(h); printf("\n最大值是:%d\n", max); printf("最大堆为:\n"); Print(h); return 0; }
最小堆:
#include"Heap.h" int main() { int maxsize = 100; Heap h = CreateHeap(maxsize); int count = 0; int input = 0; while (scanf("%d", &input) == 1 && count <= maxsize) { Insert(h, input); } int i = 0; for (i = 0; i < 10; i++) { printf("最小堆是:\n"); Print(h); int min = Delete(h); printf("\n最小值是:%d\n", min); printf("最小堆是:\n"); Print(h); } return 0; }
多分析代码,理解逐层过滤的方便之处。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。