Priority Queue(优先队列)

  今天早上起来完成了一个完整的基于二叉堆实现的优先队列,其中包含最小优先和最大优先队列。

  上篇说了优先队列的特性,通过建堆和堆排序操作,我们就已经看到了这种数据结构中的数据具有某种优先级别,要么非根节点大于他的子节点,要么就相反,在最大优先队列中最大优先级别就是指节点值最大的数据为根节点,每次出队时肯定是最大的先出去,反之则是最小优先队列,但要注意插入时的数据不一定是最大或最小的,优先队列会通过一点小技巧找到所有节点之间的关系并对应起来,重新使得你随意插入的数据满足优先队列的特性,因而这种数据结构的使用很普遍。比如:操作系统中的任务调度等。

  用线性表实现这种数据结构并不难,下面是代码:

/**
 *  PrioityQueue(优先队列)
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
 
typedef int ElemType;
 
typedef struct
{
    ElemType * arr;
    int size;
}Heap;
 
/* 全局函数 */
Heap * Initialize_Heap();
void Build_Min_Heap();
void Build_Max_Heap();
void Heap_Sort();
int Heap_Minimum();
int Heap_Maximum();
int Heap_Extract_Min();
int Heap_Extract_Max();
void Heap_Insert_Max();
void Heap_Insert_Min();
void Destroy_Heap();
 
/* 静态函数 */
static int HeapParent();
static int HeapLeft();
static int HeapRight();
static void Min_Heapify();
static void Max_Heapify();
static void Heap_Increase_Min_Key();
static void Heap_Increase_Max_Key();
 
/*
 *  初始化堆
 *     参数说明:无参数
 *
 *  返回堆
 */
Heap * Initialize_Heap(void)
{
    Heap * heap;
 
    heap = (Heap *)malloc(sizeof(Heap));
    heap -> arr = (ElemType *)malloc(sizeof(ElemType));
    heap -> size = -1;
 
    return heap;
}
 
/*
 *  节点i的双亲
 */
static int HeapParent(int i)
{
    return i/2;
}
 
/*
 *  节点i的左孩子
 */
static int HeapLeft(int i)
{
    return 2*i + 1;
}
 
/*
 *  节点i的右孩子
 */
static int HeapRight(int i)
{
    return 2*(i + 1);
}
 
/*
 *  维护最小堆的性质
 */
static void Min_Heapify(Heap * heap, int i)
{
    int l = HeapLeft(i);
    int r = HeapRight(i);
    int smallest;
    int temp;
 
    if(l < heap -> size && heap -> arr[l] < heap -> arr[i])
        smallest = l;
    else
        smallest = i;
    if(r < heap -> size && heap -> arr[r] < heap -> arr[i])
        smallest = r;
    if(smallest != i)
    {
        temp = heap -> arr[i];
        heap -> arr[i] = heap -> arr[smallest];
        heap -> arr[smallest] = temp;
        Min_Heapify(heap, smallest);
    }
}
 
/*
 *  维护最大堆的性质
 */
static void Max_Heapify(Heap * heap, int i)
{
    int _L = HeapLeft(i);
    int _R = HeapRight(i);
    int largest;
    int temp;
 
    if(_L < heap -> size && heap -> arr[_L] > heap -> arr[i])
        largest = _L;
    else
        largest = i;
    if(_R < heap -> size && heap -> arr[_R] > heap -> arr[largest])
        largest = _R;
    if(largest != i)
    {
        temp = heap -> arr[i];
        heap -> arr[i] = heap -> arr[largest];
        heap -> arr[largest] = temp;
        Max_Heapify(heap, largest);
    }
}
 
/*
 *  建最小堆
 */
void Build_Min_Heap(Heap * heap)
{
    int i;
 
    for(i = heap -> size/2; i >= 0; i--)
        Min_Heapify(heap, i);
}
 
/*
 *  建最大堆
 */
void Build_Max_Heap(Heap * heap)
{
    int i;
 
    for(i = heap -> size/2; i >= 0; i--)
        Max_Heapify(heap, i);
}
 
/*
 *  最大优先队列 - 排序
 */
void Heap_Sort(Heap * heap)
{
    int i;
    int temp;
 
    Build_Max_Heap(heap);
    for(i = heap -> size; i >= 0; i--)
    {
        temp = heap -> arr[0];
        heap -> arr[0] = heap -> arr[i];
        heap -> arr[i] = temp;
        -- heap -> size;
        Max_Heapify(heap, 0);
    }
}
 
/*
 *  最小优先队列 - 最小值
 */
int Heap_Minimum(Heap * heap)
{
    return heap -> arr[0];
}
 
/*
 *  最大优先队列 - 最大值
 */
int Heap_Maximum(Heap * heap)
{
    return heap -> arr[0];
}
 
/*
 *  最小优先队列 - 去除最小值节点
 */
int Heap_Extract_Min(Heap * heap)
{
    int min;
 
    if(heap -> size < 0)
    {
        fprintf(stderr, "Heap underflow!
");
        return 0;
    }
    min = heap -> arr[0];
    heap -> arr[0] = heap -> arr[heap -> size];
    heap -> arr[heap -> size] = min;
    -- heap -> size;
    Min_Heapify(heap, 0);
 
    return min;
}
 
/*
 *  最大优先队列 - 去除最大值节点
 */
int Heap_Extract_Max(Heap * heap)
{
    int max;
 
    if(heap -> size < 0)
    {
        fprintf(stderr, "Heap underflow!
");
        return 0;           //提前退出
    }
    max = heap -> arr[0];
    heap -> arr[0] = heap -> arr[heap -> size];
    -- heap -> size;
    Max_Heapify(heap, 0);
 
    return max;
}
 
/*
 *  将key的值赋给节点i。此处将key值插入最小堆中
 *
 *  参数说明:
 *      1.接收一个已存在的堆
 *      2.节点位置
 *      3.与堆节后数据相同类型的键值
 */
static void Heap_Increase_Min_Key(Heap * heap, int i, ElemType key)
{
    int temp;
 
    if(key > heap -> arr[i])
    {
        printf("请输入小于当前节点值的数据
");
        return ;
    }
    heap -> arr[i] = key;
    while(i > 0 && heap -> arr[HeapParent(i)] > heap -> arr[i])
    {
        temp = heap -> arr[i];
        heap -> arr[i] = heap -> arr[HeapParent(i)];
        heap -> arr[HeapParent(i)] = temp;
        i = HeapParent(i);
    }
}
 
/*
 *  将key的值赋给节点i。此处将key值插入最大堆中
 *
 *  参数说明:
 *      1.接收一个已存在的堆
 *      2.节点位置
 *      3.与堆节后数据相同类型的键值
 */
static void Heap_Increase_Max_Key(Heap * heap, int i, ElemType key)
{
    int temp;
 
    if(key < heap -> arr[i])
    {
        printf("请输入大于当前节点值的数据
");
        return ;
    }
    heap -> arr[i] = key;
    while(i > 0 && heap -> arr[HeapParent(i)] < heap -> arr[i])
    {
        temp = heap -> arr[i];
        heap -> arr[i] = heap -> arr[HeapParent(i)];
        heap -> arr[HeapParent(i)] = temp;
        i = HeapParent(i);
    }
}
 
/*
 *  将key值插入最小堆
 */
void Heap_Insert_Min(Heap * heap, ElemType key)
{
    ++ heap -> size;
    heap -> arr[heap -> size] = 65533;
    Heap_Increase_Min_Key(heap, heap -> size, key);
}
 
/*
 *  将key值插入最大堆
 */
void Heap_Insert_Max(Heap * heap, ElemType key)
{
    ++ heap -> size;
    heap -> arr[heap -> size] = -65533;
    Heap_Increase_Max_Key(heap, heap -> size, key);
}
 
/*
 *  如果堆存在则销毁堆
 *
 *  无参数/返回值
 */
void Destroy_Heap(Heap * heap)
{
    if(heap && heap -> arr)
    {
        free(heap -> arr);
        free(heap);
        heap = NULL;
    }
}

// 主函数
int main(void)
{
    ElemType val;
    Heap * heap;
    char c;
    int i, cont = 0;
 
    heap = Initialize_Heap();
 
    puts("1) Insert Heap    2) Extract Max");
    puts("3) Display  4) Exit");
 
    while((c = getch()) != '4')
    {
        switch(c)
        {
            case '1' :  cont ++;
                        printf("Enter key:");
                        scanf("%d", &val);
                        Heap_Insert_Max(heap, val);
                break;
            case '2' :  cont --;
                        printf("Max key = %d
", Heap_Extract_Max(heap));
                break;
            case '3' :  Build_Max_Heap(heap);
                        printf("显示数据:
");
                        for(i = 0; i < cont; i++)
                            printf("%d ", heap -> arr[i]);
                        printf("NULL
");
                break;
        }
    }
    // Destroy_Heap();
 
    return 0;
}

  参考资料:1.《算法导论》- 堆排序 (84~93)。

       2.百度百科 - 优先队列

       3.百度百科 - 堆

原文地址:https://www.cnblogs.com/darkchii/p/7595189.html