最小对/优先队列(C语言实现)
- 最小堆 / 优先队列(C语言实现)
- 转自网址:http://www.2cto.com/kf/201404/293694.html
- 2014-04-17 0个评论 来源:最小堆 / 优先队列(C语言实现)
- 收藏 我要投稿
-
最近找实习,复习下数据结构方面的内容。
完全二叉树有两种形态,一种是:二叉树的所有子树要么没有孩子,要么一定有左孩子。另一种是:二叉树要么没有子树,要么一定左右子树都有。
堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于(或不小于)其左孩子和右孩子节点的值。
最大堆和最小堆是二叉堆的两种形式。
最大堆:根结点的键值是所有堆结点键值中最大者。
最小堆:根结点的键值是所有堆结点键值中最小者。
在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高进先出 (largest-in,first-out)的行为特征。优先队列可以用堆来实现。
-
下面我们用数组来实现一个最小堆。
代码如下:
MinHeap.h
?#ifndef DataStructures_MinHeap_h
#define DataStructures_MinHeap_h
struct MinHeap;
typedef struct MinHeap * MinPriorityQueue;
typedef
int
ElementType;
// 初始化堆
MinPriorityQueue initialize(
int
maxElements);
// 销毁堆
void
destroy(MinPriorityQueue pqueue);
// 清空堆中的元素
void
makeEmpty(MinPriorityQueue pqueue);
// 插入操作
void
insert(ElementType x, MinPriorityQueue pqueue);
// 删除最小者操作,返回被删除的堆顶元素
ElementType deleteMin(MinPriorityQueue pqueue);
// 查找最小者(堆顶)
ElementType findMin(MinPriorityQueue pqueue);
// 判断堆是否为空
int
isEmpty(MinPriorityQueue pqueue);
// 判断堆是否满
int
isFull(MinPriorityQueue pqueue);
// 通过一个数组来建堆,相当于将用数组实现的无序树转换为堆序树
MinPriorityQueue buildHeap_insert(
int
*arr,
int
n);
MinPriorityQueue buildHeap_percolate(
int
*arr,
int
n);
// 打印堆
void
printMinPriorityQueue(MinPriorityQueue pqueue);
#endif
MinHeap.c
?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309#include <stdio.h>
#include <stdlib.h>
#include
"MinHeap.h"
/* 标记节点,类似于链表中的表头节点
* 该值必须小于所有最小堆中的元素,设其值为-1
*/
#define SentinelElement -
1
/*
* 使用数组实现堆
*
* capacity 数组的最大容量
* size 数组的长度
* elements 堆中的元素存放的数组
*/
struct MinHeap
{
int
capacity;
int
size;
ElementType *elements;
// 堆的元素个数为size,实际上用来存储的数组的长度为size + 1,还包括一个sentinel元素
};
void
PQueueNULLWarning()
{
printf(
"Warning: Minimum Priority Queue is NULL"
);
}
void
outOfSpaceFatalError()
{
printf(
"Fatal Error: Out of space"
);
abort();
}
MinPriorityQueue
initialize(
int
maxElements)
{
MinPriorityQueue pqueue;
if
(maxElements <=
0
)
{
printf(
"Fail to initialize: maxElements <= 0"
);
return
NULL;
}
pqueue = malloc(sizeof(struct MinHeap));
if
(pqueue == NULL)
outOfSpaceFatalError();
// 数组的第0个元素是个sentinel标记节点,计入数组容量中,但不计入capcaity或size中
pqueue->size =
0
;
pqueue->capacity = maxElements;
pqueue->elements = malloc(sizeof(ElementType) * (pqueue->capacity +
1
));
if
(pqueue->elements == NULL)
outOfSpaceFatalError();
else
pqueue->elements[
0
] = SentinelElement;
return
pqueue;
}
void
destroy(MinPriorityQueue pqueue)
{
if
(pqueue != NULL)
{
// 在GNU99标准中,free(NULL)什么都不做直接返回,所以不用判断pqueue->elements是否为NULL
free(pqueue->elements);
free(pqueue);
}
}
void
makeEmpty(MinPriorityQueue pqueue)
{
if
(pqueue != NULL)
pqueue->size =
0
;
else
PQueueNULLWarning();
}
/*
* 插入时,堆中的元素执行下滤操作
* 删除时,堆中的元素执行上滤操作
*/
/*
* 插入的时间复杂度为O(log N),N为最小堆中的元素个数
* 实际上,其平均执行时间为O(1)
*/
void
insert(ElementType x, MinPriorityQueue pqueue)
{
if
(pqueue == NULL)
PQueueNULLWarning();
if
(isFull(pqueue))
{
printf(
"Fail to insert: Priority Queue is Full"
);
return
;
}
else
{
int
i;
// sentinel element在这里作为elements[0]被比较,是循环的终止条件
for
(i = ++pqueue->size; x < pqueue->elements[i /
2
]; i /=
2
)
pqueue->elements[i] = pqueue->elements[i /
2
];
// 下滤操作
pqueue->elements[i] = x;
}
}
/*
* 删除操作的平均时间为O(log N)
*/
ElementType
deleteMin(MinPriorityQueue pqueue)
{
if
(pqueue == NULL)
{
PQueueNULLWarning();
return
SentinelElement;
}
if
(isEmpty(pqueue))
{
printf(
"Fail to delete: Priority Queue is Empty"
);
return
SentinelElement;
}
int
i, child;
ElementType minElement, lastElement;
// 注意对某个节点进行上滤操作时,要判断该节点是有两个儿子还是一个儿子
minElement = pqueue->elements[
1
];
lastElement = pqueue->elements[pqueue->size--];
for
(i =
1
; i *
2
<= pqueue->size; i = child)
{
child = i *
2
;
// 节点i只有一个儿子时必有i * 2 = pqueue->size
if
(child < pqueue->size && pqueue->elements[child] > pqueue->elements[child +
1
])
child++;
if
(lastElement < pqueue->elements[child])
break
;
else
pqueue->elements[i] = pqueue->elements[child];
// 上滤操作
}
pqueue->elements[i] = lastElement;
return
minElement;
// 返回被删除的元素
}
/*
* 执行时间:O(1)
*/
ElementType
findMin(MinPriorityQueue pqueue)
{
if
(pqueue == NULL)
{
PQueueNULLWarning();
return
SentinelElement;
}
else
return
pqueue->elements[
1
];
}
int
isEmpty(MinPriorityQueue pqueue)
{
if
(pqueue == NULL)
{
PQueueNULLWarning();
return
-
1
;
}
else
return
(pqueue->size ==
0
);
}
int
isFull(MinPriorityQueue pqueue)
{
if
(pqueue == NULL)
{
PQueueNULLWarning();
return
-
1
;
}
else
return
(pqueue->size == pqueue->capacity);
}
void
percolateDown(
int
*arr,
int
len,
int
i)
{
int
n = len -
1
;
int
tmp;
if
(i *
2
== n && arr[i] > arr[n])
// 只有左儿子的节点,并且左儿子比本节点的值要小,交换
{
tmp = arr[i];
arr[i] = arr[n];
arr[n] = tmp;
}
else
// 有两个儿子的节点
{
if
(arr[i *
2
] > arr[i *
2
+
1
])
// 右儿子较小
{
if
(arr[i] > arr[i *
2
+
1
])
// 如果本节点比右儿子大,交换
{
tmp = arr[i];
arr[i] = arr[i *
2
+
1
];
arr[i *
2
+
1
] = tmp;
}
}
else
// 左儿子较小
{
if
(arr[i] > arr[i *
2
])
// 如果本节点比左儿子大,交换
{
tmp = arr[i];
arr[i] = arr[i *
2
];
arr[i *
2
] = tmp;
}
}
}
}
MinPriorityQueue
buildHeap_percolate(
int
*arr,
int
n)
{
if
(arr == NULL)
{
printf(
"Error: Array is NULL"
);
return
NULL;
}
MinPriorityQueue pqueue;
pqueue = malloc(sizeof(struct MinHeap));
if
(pqueue == NULL)
outOfSpaceFatalError();
ElementType *elements = malloc(sizeof(ElementType) * (n +
1
));
if
(elements == NULL)
outOfSpaceFatalError();
int
i;
for
(i =
1
; i <= n; i++)
elements[i] = arr[i -
1
];
elements[
0
] = SentinelElement;
for
(i = n /
2
; i >
0
; i--)
percolateDown(elements, n +
1
, i);
pqueue->elements = elements;
pqueue->size = n;
pqueue->capacity = n *
2
;
return
pqueue;
}
/*
* 通过n次插入元素建立堆,由于每次插入的平均执行时间为O(1),所以建堆平均时间为O(N)
*/
MinPriorityQueue
buildHeap_insert(
int
*arr,
int
n)
{
MinPriorityQueue pqueue;
if
(arr == NULL)
{
printf(
"Array is NULL, fail to build heap"
);
return
NULL;
}
pqueue = initialize(n *
2
);
for
(
int
i =
0
; i < n; i++)
insert(arr[i], pqueue);
return
pqueue;
}
void
printMinPriorityQueue(MinPriorityQueue pqueue)
{
if
(pqueue == NULL)
{
PQueueNULLWarning();
return
;
}
if
(pqueue->elements == NULL)
{
printf(
"Fail to print: Elements of priority queue is NULL"
);
return
;
}
if
(isEmpty(pqueue))
{
printf(
"Empty Prioirty Queue\n"
);
return
;
}
printf(
"Priority Queue\n"
);
for
(
int
i =
1
; i <= pqueue->size; i++)
printf(
"Element[%d] = %d\n"
, i, pqueue->elements[i]);
printf(
"\n"
);
}</stdlib.h></stdio.h>
建堆的测试代码:
?123456789101112131415#include <stdio.h>
#include <stdlib.h>
#include
"MinHeap.h"
int
main(
int
argc,
const
char
* argv[])
{
int
a[
5
] = {
5
,
4
,
3
,
2
,
1
};
MinPriorityQueue pqueue_ins = buildHeap_insert(a,
5
);
MinPriorityQueue pqueue_per = buildHeap_percolate(a,
5
);
printMinPriorityQueue(pqueue_ins);
printMinPriorityQueue(pqueue_per);
return
0
;
}</stdlib.h></stdio.h>
分别使用插入和下滤两种方式建堆,所以建立的结果是不同的,输出如下:
?12345678910111213Priority Queue
Element[
1
] =
1
Element[
2
] =
2
Element[
3
] =
4
Element[
4
] =
5
Element[
5
] =
3
Priority Queue
Element[
1
] =
1
Element[
2
] =
5
Element[
3
] =
3
Element[
4
] =
2
Element[
5
] =
4
最大堆实现类似。
最小对/优先队列(C语言实现)相关推荐
- 数据结构之优先队列:最小索引优先队列,Python代码实现——15
最小索引优先队列(Min index priority queue) 在之前实现的最大优先队列和最小优先队列,他们可以分别快速访问到队列中最大元索和最小元素,但是他们有一 个缺点,就是没有办法通过索引 ...
- leetcode 703. 数据流中的第K大元素 最小堆解法 c语言
如题: 设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含 ...
- LeetCode 1962. 移除石子使总数最小(优先队列)
文章目录 1. 题目 2. 解题 1. 题目 给你一个整数数组 piles ,数组 下标从 0 开始 ,其中 piles[i] 表示第 i 堆石子中的石子数量. 另给你一个整数 k ,请你执行下述操作 ...
- 流网络的最小割问题c语言,「网络流24题」最小路径覆盖问题
Description 问题描述: 给定有向图G=(V,E).设P 是G 的一个简单路(顶点不相交)的集合.如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖.P 中路径可以从V 的任 ...
- ieee754最小规格化正数C语言,IEEE754标准浮点格式
两种基本浮点格式:单精度和双精度.IEEE单精度格式具有24位有效数字,并总共占用32 位.IEEE双精度格式具有53位有效数字精度,并总共占用64位 两种扩展浮点格式:单精度扩展和双精度扩展.此标准 ...
- 找出矩阵在行中最大、列中最小的元素 C语言
函数fun的功能是:在3x4的矩阵中找出在行上最大.在列上最小的那个元素,若没有符合条件的元素则输出相应信息. 例如有下列矩阵: 1 2 13 4 7 8 10 6 3 5 9 7 程序 ...
- 华为OD机试 - 数组组成的最小数字(C 语言解题)【独家】
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单 华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典 [华为OD机试]全流程解析+经验分享,题型分 ...
- 流网络的最小割问题c语言,网络流基础-最大流最小割定理
最大流最小割定理,指网络流的最大流等于其最小割. 最大流指符合三个性质的前提下,从S到T能流过的最大流量. 最小割指符合割的定义,最小的割容量. 求最大流: 不断寻找增广路,计算能增加的最小流量,然后 ...
- 数据结构——最大堆和最小堆(C语言)
定义: 最大堆和最小堆都是一棵完全二叉树. 最大堆:是指根节点的关键字值是堆中的最大关键字值,且每个节点若有儿子节点,其关键字值都不小于其儿子节点的关键字值. 最小堆:是指根节点的关键字值是堆中的最小 ...
- 矩阵连乘最小计算次数 C语言
先上代码 #include <stdio.h> #include <algorithm> #include <string.h> #include <cmat ...
最新文章
- python rfind函数用法_Python语法速查:字符串格式简单处理、子串查找与判断方法?...
- springcloud 入门 10 (eureka高可用)
- Leetcode--130. 被围绕的区域(java)
- (vue基础试炼_04)使用组件改造TodoList
- python算法系列资料集(一)-2022.03.15
- 西安python后端招聘_有大佬招 Python 后端初级人员吗?
- serialize和unserialize函数
- 用ABAP编程破解世界上最难数独游戏
- html播放flv直播源,http-flv 直播
- python模拟支付宝扫码登录_Python接入支付宝进行PC端支付
- 【BZOJ4198】【NOI2015】荷马史诗(贪心,Huffman树)
- kali获取同局域网设备的图片信息
- 安装ie9提示未能完成安装_win10系统安装iE提示“internet Explorer未能完成安装”的方法介绍...
- 《深入理解计算机系统》——低谷中的重新振作
- Pro Android学习笔记(一五五):传感器(5): 磁场传感器和方位(上)
- python均线斜率_【每日一策】Matlab量化交易策略之 均线拐头配合出场
- 弘辽科技:拼多多关键词怎么添加?店铺没转化咋办?
- aseprite手机版_texture packs泰拉瑞亚
- [luoguP2862] [USACO06JAN]把牛Corral the Cows(二分 + 乱搞)
- Go 语言 exec 实时获取外部命令的执行输出