最大优先队列

最大优先队列

前言

堆排序是一种集插入排序和选择排序的有点于一身的排序算法,但是在后面能学习到更加好的快速排序算法,性能优于堆排序。堆这钟数据结构还有许多其他的用处,例如作为高效的优先队列。优先队列分为最大优先队列和最小优先队列,今天学习了如何用最大堆来实现最大优先队列。

优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中的每一个元素都有一个相关的值,称为关键字。一个最大优先队列应该支持下面的四种操作:

  1. MAXIMUM(S):将集合S中的最大关键字的元素返回。
  2. EXTRACT_MAX(S):返回并去掉S中最大的元素。
  3. INCREASE_KEY(S,x,k):将集合S中的x元素关键字的值提升至k,假设k不小于原x的关键字值。
  4. INSERT(S,x):将元素x插入集合S中。

原理

最大优先队列是建立在最大堆上的,在上一篇中已经学习到了关于最大堆的一些知识。在进行上述的四种操作前需要建立一个最大堆。对四种操作的解析如下:

  1. MAXIMUM(S) : 根据最大堆的性质,拥有最大关键字值的一项永远在索引为0的地方,所以直接返回即可。
  2. EXTRACT_MAX(S) : 将最大项和堆中的最后一项交换值,并返回最大项,需要删除最大项,可以将整个堆的大小缩小一项,不用理会最后一项(最后一项即交换成了最大项),第一项变化后需要对最大堆进行调整,也就是上篇博客中提到的向下调整。
  3. INCREASE_KEY(S,x,k) : 将元素x的关键字值提升到了k之后,x下面的子树肯定是没有被破坏的,向上不断和x的父节点比较关键字值,如果key(x)>key(parent(x)),则交换值。

  4. INSERT(S,key) : 在最大堆的最后一项后面加上一项。赋值为key,之后需要进行的就是对整个堆的调整,即从最后一项开始进行上面的第三步操作(INCREASE_KEY(S,x,k))。

C语言实现

//针对节点i及其子树进行最大堆的调整
void max_heapify(int* a, int i, int count)
{
    int left_index , right_index ;
    int max_index = i;
    left_index = 2 * i + 1;
    right_index = left_index + 1;
    if ((left_index <= count) && (a[left_index] > a[max_index]))
        max_index = left_index;
    if ((right_index <= count) && (a[right_index] > a[max_index]))
            max_index = right_index;
    if (max_index != i)
    {
        int t = a[i];
        a[i] = a[max_index];
        a[max_index] = t;
        max_heapify(a, max_index, count);
    }
}

//建立最大堆
void build_max_heap(int* a, int count)
{
    for (int i = count / 2; i >= 0; i--)
    {
        //对每个子根节点进行堆调整
        max_heapify(a, i, count);
    }
}

//返回优先度最大的对象
int heap_maximum(int* a)
{
    return a[0];
}

//返回并删除优先度最大的对象
int heap_extract_max(int* a, int count)
{
    if (count < 1)
        return -1;
    int max = a[0];
    a[0] = a[count];
    max_heapify(a, 0, count - 1);
    return max;
}

//增加元素的优先度
void heap_increase_key(int* a, int i, int key)
{
    if (a[i] >= key)
        return;
    a[i] = key;
    while (i > 0 && a[(i - 1) / 2] < a[i])
    {
        int t = a[(i - 1) / 2];
        a[(i - 1) / 2] = a[i];
        a[i] = t;
        i = (i - 1) / 2;
    }
}

//插入元素
int* heap_insert(int* a, int key, int count)
{
    int* p = (int*)malloc((count + 1) * 2);
    for (int i = 0; i < count; i++)
    {
        p[i] = a[i];
    }
    p[count] = -1;
    heap_increase_key(p, count, key);
    return p;
}

void main()
{
    int count, *p;
    printf("请输入需要排序的数的个数 :");
    scanf_s("%d", &count);
    p = (int*)malloc(count * 2);
    printf("\n请输入需要排序的%d个数字:",count);
    for (int i = 0; i < count; i++)
    {
        scanf_s("%d", p+i);
    }
    //依据输入的一列数字,建出一个最大堆
    build_max_heap(p, count - 1);
    printf("建立最大堆后的数组:");
    for (int i = 0; i < count; i++)
    {
        printf("%d ", p[i]);
    }
    printf("\n\n");

    printf("最大元素为:%d\n", heap_maximum(p));
    printf("\n\n");
    printf("弹出最大元素:%d, 当前堆为:", heap_extract_max(p, count - 1));
    count--;
    for (int i = 0; i < count; i++)
    {
        printf("%d ", p[i]);
    }
    printf("\n\n");
    printf("增大第5个元素的优先度为10, 当前堆为:");
    heap_increase_key(p, 4, 10);
    for (int i = 0; i < count; i++)
    {
        printf("%d ", p[i]);
    }
    printf("\n\n");
    printf("插入一个优先度为100的元素,当前堆为:");
    p = heap_insert(p, 100, count);
    for (int i = 0; i < count + 1; i++)
    {
        printf("%d ", p[i]);
    }
    system("pause");
}
时间: 2024-10-09 17:25:36

最大优先队列的相关文章

51nod1428(优先队列)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1428 题意:中文题诶- 思路:贪心 问最少要多少教室就是求最多有多少个时间段产生了交集咯.我们先用结构体存储区间并将其按照左端点升序排列,若左端点相同则按右端点升序排列. 接下来遍历所有区间,并维护一个优先队列,其中存储区间右端点值.对于当前区间,我们将优先队列中所有比当前区间左端点小的元素删除(因为其所在区间不会与当前区间相交嘛),然后再将当前区间的右端点加

优先队列实现哈弗曼最小权值

建立哈弗曼树要求我们每次都选频率权值最小的点构成节点,即权值小的点在树的深处,权值大的点在树的浅处,根据节点选择的特点,我们可以把节点的值放在优先队列中,包括新形成的节点. 我们先定义优先队列的优先级别. 1 struct cmp 2 { 3 bool operator()(const int &a,const int &b) 4 { 5 return a>b; 6 } 7 };//最小值优先出队 然后就是实现的整个程序. #include<stdio.h> #inclu

NYOJ 284 坦克大战 &amp;&amp; POJ 2312 Battle City (广搜+优先队列)

链接:click here~~ 题意: 描述 Many of us had played the game "Battle city" in our childhood, and some people (like me) even often play it on computer now. What we are discussing is a simple edition of this game. Given a map that consists of empty space

hdu 4006 The kth great number(优先队列)

The kth great number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 6982    Accepted Submission(s): 2837 Problem Description Xiao Ming and Xiao Bao are playing a simple Numbers game. In a roun

优先队列(堆)

一.优先队列的一些简单的实现: 1. 使用一个简单的链表在表头以O(1) 执行插入操作,并遍历该链表以删除最小元,这需要O(N) 的时间. 2. 始终让表保持有序状态:这使得插入代价高昂(O(N)), 而删除代价低廉(O(1)).基于删除最小元的操作从不多于插入操作的事实,因此,前者是更好地想法. 3. 使用二叉查找树,它对这两种操作的平均运行时间是O(logN).尽管插入是随机的,而删除不是,但这个结论还是成立的.由于删除的唯一元素是最小元.反复除去左子树中的节点似乎损害树的平衡,使得右子树加

优先队列比较符重载

#include <iostream> #include <queue> using namespace std; struct Node{ int x, y; friend bool operator<(Node a, Node b){ return a.x > b.x; //x最小的节点在队首 } }; int main(){ priority_queue<Node> PQ; Node temp = {2, 3}; PQ.push(temp); temp

[ACM] hdu 1242 Rescue (BFS+优先队列)

Rescue Problem Description Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is described as a N * M (N, M <= 200) matrix. There are WALLs, ROADs, and GUARDs in the prison. Angel's friends want to save Angel. Their task is:

1475 建设国家(优先队列)

1475 建设国家 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 小C现在想建设一个国家.这个国家中有一个首都,然后有若干个中间站,还有若干个城市. 现在小C想把国家建造成这样的形状:选若干(可以是0个)的中间站把他们连成一条直线,然后把首都(首都也是一个中间站)连在这一条直线的左端.然后每个点可以连一个城市,特别的是最右端的点可以连接两个城市. 现在有n个城市的规划供小C选择.但是,他们那儿的交通条件比较差,他们那儿一天是2*H个小时,每个城市里面的人每天

Battle City BFS+优先队列

Battle City Many of us had played the game "Battle city" in our childhood, and some people (like me) even often play it on computer now. What we are discussing is a simple edition of this game. Given a map that consists of empty spaces, rivers,

堆与优先队列

当我们需要高效的完成以下操作时: 1.插入一个元素 2.取得最小(最大)的数值,并且删除 能够完成这种操作的数据结构叫做优先队列 而能够使用二叉树,完成这种操作的数据结构叫做堆(二叉堆) 堆与优先队列的时间复杂度: 若共有n个元素,则可在O(logn)的时间内完成上述两种操作 堆的结构如下图: 堆最重要的性质就是儿子的值一定不小于父亲的值,且堆从上到下,从左到右紧密排列. 堆的操作: 当我们希望向堆中插入元素时,堆的内部会进行如下操作(以插入元素3为例): (1.在堆的末尾插入该值) (2.不断