数据结构与算法—复习:堆 优先队列
优先队列的精髓:
-
插入算法:
该算法从优先队列的序列去观察,比较直观。首先把要插入的元素放在队尾temp里。从队列的最后一个元素,逐次向前寻找父节点,空位随之移动,当到达队头,或者当前元素小于temp元素时,即可插入。 -
删除算法:
删除最小元素,也就是最头的元素。当我们利用(当前元素数量)-1 这样的操作删除元素后,最后一个元素便被排空了出来,所以主要任务便是安排最后一个元素的落点。从队头开始,用两个指针,分别指向父结点和子结点,当子结点未到达队尾,循环条件成立。首先在子结点中挑选一个较小的。然后再判断,temp(放入队尾元素的)是否大于这个最小的子结点,如果是,则 指针2 -> 指针2 的子结点,指针1 -> 指针2。再次循环。如果temp小于这个最小的子结点,则说明发现合适的位置,可以直接插入。当循环结束,也未发现temp < 子结点 的位置时,循环结束,此时的指针1位置,便是最佳位置。堆序性:每个根结点<每个子结点 或 每个根结点>每个子结点
/**
* 程序说明:复习 堆 优先队列
* 优先队列---堆来存储
* 1.插入
*/
#include <stdio.h>
#include <malloc.h>
/**
* 优先队列定义
* 与顺序存储的二叉树一致
*/
struct PriorityQueue{
int MAXNUM; //最大长度
int n; //当前数量
int* val; //数据类型
};
typedef struct PriorityQueue* PPriorityQueue;
/**
* 优先队列 创建空的优先队列
* @param m
* @return
*/
PPriorityQueue createNullPriorityQueue(int m){
PPriorityQueue papq = (PPriorityQueue)malloc(sizeof(struct PriorityQueue));
if(papq != NULL){
papq->val = (int*)malloc(sizeof(int)*m);
if(papq->val){
papq->n = 0;
papq->MAXNUM = m;
return papq;
}
printf("创建失败\n");
return NULL;
}
printf("创建失败\n");
return NULL;
}
/**
* 给定数据,初始化优先队列
* @param papq
*/
void init(PPriorityQueue papq){
int datas[] = {2,3,5,9,10,7,8,14,12,11,16};
if(papq->n == papq->MAXNUM){
printf("优先队列已满\n");
return;
}
int size = sizeof(datas) / sizeof(int);
for (int i = 0; i < size; ++i) {
papq->val[i] = datas[i];
papq->n ++;
}
printf("初始化完毕\n");
}
/**
* 优先队列打印方法
* @param papq
*/
void printPQ(PPriorityQueue papq){
if(papq->n == 0){
printf("队列为空,无法打印\n");
return;
}
for (int i = 0; i < papq->n; ++i) {
if(i == papq->n - 1){
printf("%d",papq->val[i]);
printf("\n");
}else{
printf("%d,",papq->val[i]);
}
}
}
int isEmpty_heap(PPriorityQueue papq){
return papq->n == 0;
}
/**
* 优先队列 插入数据
* @param papq
* @param data
*/
void add_heap(PPriorityQueue papq,int data){
if(papq->n == papq->MAXNUM){
printf("优先队列已满,无法插入\n");
return;
}
int i = 0;
for (i = papq->n; i > 0 && papq->val[(i-1)/2] > data; i = (i-1)/2) {
papq->val[i] = papq->val[(i-1) / 2];
}
papq->val[i] = data; papq->n++;
}
void removeMin_heap(PPriorityQueue papq){
int i = 0, //指向当前根节点
child = 1, //指向当前根节点的左子结点
temp = 0, //存放最后一个元素
s = 0; //对标当前优先队列中的元素数量
s = --papq->n; //先删除元素
temp = papq->val[s]; //最后一个数据放在temp中
while (child < s) //当子节点还没超出队列范围时
{
if (child < s - 1 && papq->val[child] > papq->val[child+1]){ //选择较小的节点{
child++;
}
if(temp > papq->val[child]){ //若最后一个元素大于当前子节点,那么令i =child child = 2*i + 1
papq->val[i] = papq->val[child]; //去寻找下一个合适的位置
i = child; child = 2*i + 1;
} else break; //找到了合适的位置
}
papq->val[i] = temp;
}
int main() {
PPriorityQueue papq = createNullPriorityQueue(100);
init(papq);
printPQ(papq);
add_heap(papq,4);
printPQ(papq);
removeMin_heap(papq);
printPQ(papq);
removeMin_heap(papq);
printPQ(papq);
}