最小对/优先队列(C语言实现)
来源:互联网 发布:真维斯淘宝 编辑:程序博客网 时间:2024/05/22 12:45
- 最小堆 / 优先队列(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.c123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309#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
最大堆实现类似。
0 1
- 最小对/优先队列(C语言实现)
- 最小堆 / 优先队列(C语言实现)
- c语言最小堆的实现-优先队列
- 优先队列C语言实现
- 优先队列--C语言实现
- C语言队列实现广度优先遍历
- 优先队列二叉堆 C语言实现
- 数据结构 优先队列 C语言实现
- 最小堆实现优先队列解决修理牧场(c/c++)
- 最小优先队列--堆实现
- 数据结构实现之最小优先队列(最小堆)
- 优先队列(堆) - C语言实现(摘自数据结构与算法分析 C语言描述)
- 优先队列(堆) - C语言实现(摘自数据结构与算法分析 C语言描述)
- 优先队列(堆) - C语言实现(摘自数据结构与算法分析 C语言描述)
- 优先队列 C实现
- 优先队列——C语言实现、python实现
- 对队列各种操作的实现(C语言)
- 优先队列的精简实现(c++)
- 习题6-1 UVa673 Parentheses Balance(栈)
- 关于自定义控件和属性时TypedArray.getDimension应当注意的问题
- 写在前面
- 河南第三届ACM省赛(聪明的kk)
- flask源码笔记:三,app.py模块(1)——导入对象
- 最小对/优先队列(C语言实现)
- Java虚拟机体系结构深入研究总结
- 查看Jar打包的jdk版本
- web相关的基础知识
- flask源码笔记:三,app.py模块(2)——Flask的基类_PackageBoundObject
- [bzoj3289]Mato的文件管理
- Linux文件系统基础(3)
- 项目中出现的错误汇总、以及小笔记Transport Security
- java序列化、hessian和protostuff性能比较