基础知识
- 堆
堆是用数组实现的二叉树,它的逻辑结构是二叉树,存储结构是数组,所以它没有左右孩子指针。
堆(优先队列)的结构体定义为:
#define Type int
typedef struct HeapStruct{
int capacity;
int size;
Type *eles;
}PriorityQueue;
capacity是堆的最大容量,创建时进行初始化;size是已使用的容量;eles是指针,用于对数据进行操作.
-
优先队列
优先队列是利用堆的性质实现的,分两种情况,大顶堆和小顶堆。以大顶堆为例,其性质是:- 节点的左右孩子的值,都小于该节点的值
- 左右孩子也都是大顶堆.
根据优先队列的性质可以看到,大顶堆的根节点即为序列的最大值,相应的小顶堆的根节点就是序列的最小值。那么我们将一组数输入到大顶堆中,然后依次输出根节点,便实现了堆排序,这样的堆就是常用的优先队列(PriorityQueue)。
这个过程中,我们主要做的是,每插入一个元素,都要将堆调整为优先队列,同样,每删除一个根节点,也要将堆重新调整。
构建优先队列
优先队列的操作包括:
- 创建/初始化
- 判空/判满
- 插入
- 查找最值
- 删除
- 摧毁
创建
创建一个PriorityQueue结构体,并分配相应的内存,为指针eles分配capacity+1的内存。因为用数组来存储二叉树,父节点和子节点存储位置的关系是son = father/2,在插入操作中,从叶节点创建一个空穴,不断和父节点比较并上移,所以从子节点到父节点经常要取半i/2,为了操作方便,我们把数组的0号位置空出来不使用,将根节点放在i=1的位置上,因此在初始化时,分配capacity+1的内存。
PriorityQueue *init(int max_size){
//这里初始化init定义为指针函数,其返回值是指针,可以直接赋值给*pq
PriorityQueue *pq = NULL; //pq为结构体指针
//检查输入大小的合法性
if(max_size <= 0){
printf("max_size is illeagel!\n");
return NULL;
}
pq = malloc(sizeof(PriorityQueue));
if(pq == NULL){
printf("malloc failed!\n");
return NULL;
}
//下标为0的位置保留,不使用
pq->eles = malloc((max_size+1)*sizeof(Type));//为数组eles分配max_size + 1的内存
if(pq->eles == NULL){
printf("eles malloc failed!\n");
free(pq);
return NULL;
}
//初始化队列成员
memset(pq->eles, 0, (max_size+1)*sizeof(Type));
pq->capacity = max_size;
pq->size = 0;
return pq;
}
在使用时只需要
PriorityQueue *pq = init(max_size);
判空
//判断是否为空
int is_empty(PriorityQueue *pq){
if(pq == NULL) //如果指针为空
return 0;
if(pq->size == 0)
return 1;
else
return 0;
}
判满
//判断是否为满
int is_full(PriorityQueue *pq){
if(pq == NULL)
return 0;
if(pq->size == pq->capacity)
return 1;
else
return 0;
}
插入
我们在 i = size +1 的位置创建一个空穴,要插入的值value与父节点进行比较,如果大于父节点,刚将父节点与空穴交换,此时空穴的位置到了 i/2 ,然后重复上述步骤,直到 i <= 1 或value小于父节点为止,然后将value 放入到空穴里,即完成了插入操作。
以序列3, 4,7,5,8,2 为例,令capacity = 9。
- 插入3
- 插入4
空穴与其父节点 j/2 进行比较,即 4 > 3,所以父节点与3交换,j = j/2,因为 j = 1,所以操作终止,将4放入空穴 j = 1;size = size + 1;
- 插入7
以此类推。最终的结果为
序列在数组中的存储并不是有序的,直接遍历不能得到有序序列,因为它在结构上是树形的,类似于二叉树的顺序存储结构。
插入操作的完整代码如下:
int push(Type value, PriorityQueue *pq){
int i=0;
//首先判断队列是否为满
if(is_full(pq)){
printf("Queue is Full!\n");
return 0;