1.优先队列
例如在日常生活中的排队,cpu的任务管理并不是一味的遵循先来先服务的原则来进行的,有特权的人,紧急的任务是要先进行服务的,而我们就需要一种带这样的优先权重与否的数据结构来管理这些元素。
从而引出优先队列:
优先队列(Priority Queue):特殊的“队列”,取出的元素顺序是依照元素的优先权(关键字)大小,而不是元素进入队列的先后顺序。
2.什么是堆?
用数组表示的完全二叉树,堆是一种常用来实现优先队列的树形数据结构。
堆通常以树形结构组织元素,但使用数组来存储这些元素。这种方法可以高效地管理完全二叉树的结构。以下是一个更详细的解释以及如何在C语言中实现这个概念。
数组存储完全二叉树的结构
-
节点关系:
- 对于数组索引为
i
的节点:- 父节点 的索引为 i
- 左子节点 的索引为
2 * i
- 右子节点 的索引为
2 * i + 1
- 对于数组索引为
-
数组表示的优势:
- 存储紧凑:避免了使用指针的开销。
- 快速访问:可以通过数组索引快速定位父节点和子节点。
3. 有序性:任一结点的关键字是其子树所有结点的最大值(或最小值) 。
最大堆
任一结点的关键字是其子树所有结点的最大值。
最小堆
任一结点的关键字是其子树所有结点的最小值。
3.堆的抽象数据类型描述
类型名称:最大堆(MaxHeap)
数据对象集:完全二叉树,每个结点的元素值不小于其子结点的元素值
操作集:最大堆H ∈ MaxHeap,元素item ∈ ElementType,主要操作有:
•MaxHeap Create( int MaxSize ):创建一个空的最大堆。
•Boolean IsFull( MaxHeap H ):判断最大堆H是否已满。
•Insert( MaxHeap H, ElementType item ):将元素item插入最大堆H。
•Boolean IsEmpty( MaxHeap H ):判断最大堆H是否为空。
•ElementType DeleteMax( MaxHeap H ):返回H中最大元素(高优先级)。
4.堆的创建
typedef struct HeapStruct *MaxHeap;
struct HeapStruct {
ElementType *Elements; /* 存储堆元素的数组 */
int Size; /* 堆的当前元素个数 */
int Capacity; /* 堆的最大容量 */
}
MaxHeap Create( int MaxSize )
{ /* 创建容量为MaxSize的空的最大堆 */
MaxHeap H = malloc( sizeof( struct HeapStruct ) );
H->Elements = malloc( (MaxSize+1) * sizeof(ElementType));
H->Size = 0;
H->Capacity = MaxSize;
H->Elements[0] = MaxData;
/* 定义“哨兵”为大于堆中所有可能元素的值,便于以后更快操作 */
return H;
}
5.堆的插入
图示:
代码:
void Insert( MaxHeap H, ElementType item )
{ /* 将元素item 插入最大堆H,其中H->Elements[0]已经定义为哨兵 */
int i;
if ( IsFull(H) ) {
printf("最大堆已满");
return;
}
i = ++H->Size; /* i指向插入后堆中的最后一个元素的位置 */
for ( ; H->Elements[i/2] < item; i/=2 ){
H->Elements[i] = H->Elements[i/2]; /* 向上过滤结点 */
}
H->Elements[i] = item; /* 将item 插入 */
}
6.堆的删除
图示:
但是堆中就那几个空子,删一个就要补回来,为了方便选择最后一个结点!
在从上面开始向下过滤,选一个最大的儿子换下去。
调整完成!
代码:
ElementType DeleteMax( MaxHeap H )
{ /* 从最大堆H中取出键值为最大的元素,并删除一个结点 */
int Parent, Child;
ElementType MaxItem, temp;
if ( IsEmpty(H) ) {
printf("最大堆已为空");
return;
}
MaxItem = H->Elements[1]; /* 取出根结点最大值 */
/* 用最大堆中最后一个元素从根结点开始向下过滤下层结点 */
temp = H->Elements[H->Size--];
for( Parent=1; Parent*2<=H->Size; Parent=Child ) {
Child = Parent * 2;
if( (Child!= H->Size) && (H->Elements[Child] < H->Elements[Child+1]) )
Child++; /* Child指向左右子结点的较大者 */
if( temp >= H->Elements[Child] ) break;
else /* 移动temp元素到下一层 */
H->Elements[Parent] = H->Elements[Child];
}
H->Elements[Parent] = temp;
return MaxItem;
}
7.完整示例
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
typedef struct HeapStruct {
ElementType *Elements; /* 存储堆元素的数组 */
int Size; /* 堆的当前元素个数 */
int Capacity; /* 堆的最大容量 */
} *MaxHeap;
MaxHeap Create(int MaxSize) {
MaxHeap H = malloc(sizeof(struct HeapStruct));
H->Elements = malloc((MaxSize + 1) * sizeof(ElementType)); // 注意:从1开始存储元素,0位置为哨兵
H->Size = 0;
H->Capacity = MaxSize;
H->Elements[0] = INT_MAX; // 哨兵值,设为比所有元素都大的值
return H;
}
int IsFull(MaxHeap H) {
return H->Size == H->Capacity;
}
int IsEmpty(MaxHeap H) {
return H->Size == 0;
}
void Insert(MaxHeap H, ElementType item) {
int i;
if (IsFull(H)) {
printf("最大堆已满\n");
return;
}
i = ++H->Size; // i指向插入后堆中的最后一个元素的位置
for (; H->Elements[i / 2] < item; i /= 2)
H->Elements[i] = H->Elements[i / 2]; // 向下过滤结点
H->Elements[i] = item; // 将item插入
}
ElementType DeleteMax(MaxHeap H) {
int Parent, Child;
ElementType MaxItem, temp;
if (IsEmpty(H)) {
printf("最大堆已为空\n");
return -1; // 假设元素类型为int,返回-1表示错误
}
MaxItem = H->Elements[1]; // 取出根结点最大值
temp = H->Elements[H->Size--];
for (Parent = 1; Parent * 2 <= H->Size; Parent = Child) {
Child = Parent * 2;
if ((Child != H->Size) && (H->Elements[Child] < H->Elements[Child + 1]))
Child++;
if (temp >= H->Elements[Child])
break;
else
H->Elements[Parent] = H->Elements[Child];
}
H->Elements[Parent] = temp;
return MaxItem;
}
void PrintHeap(MaxHeap H) {
int i;
for (i = 1; i <= H->Size; i++) {
printf("%d ", H->Elements[i]);
}
printf("\n");
}
void Destroy(MaxHeap H) {
free(H->Elements);
free(H);
}
int main() {
MaxHeap H = Create(10); // 创建一个容量为10的最大堆
Insert(H, 10);
Insert(H, 20);
Insert(H, 15);
Insert(H, 30);
Insert(H, 40);
Insert(H, 50);
printf("堆中的元素为:");
PrintHeap(H);
printf("删除最大元素: %d\n", DeleteMax(H));
printf("删除最大元素: %d\n", DeleteMax(H));
printf("删除后堆中的元素为:");
PrintHeap(H);
Destroy(H);
return 0;
}