堆与优先队列

堆与优先队列详解

堆与优先队列

(2017.7.19)

这几天刚从学校大佬那里了解到堆与优先队列,其方法实现确实很巧妙,

所以在此整理了一下。


完全二叉树:

若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边(区别与二叉树),这就是完全二叉树。(上图即是完全二叉树,是二叉树的一种特例)。


好了,接下来让我们正式进入堆的世界。

堆是数据结构的一种,可以用树来实现,称为堆树。

堆通常是用数组来实现,对比上图,如int array[] = { 1, 2, 3, 17, 19, 36, 7, 25, 100}, 数组第一个元素是从下标0开始的,对于第 i个元素, 其父节点的下标为

(i - 1)/ 2(这里的除法为编程中的除法)。其左右节点的下标分别为

2 * i + 12 * i + 2.

堆通常分为最大堆和最小堆(其他的种类很少用到)

最大堆是指每一个父节点总是大于其子节点,所以堆顶为堆中最大的元素。

最小堆是指每一个父节点总是小于其子节点,所以堆顶为堆中最小的元素。

对于堆中的节点和节点之间并没有严格的大小关系(上图即可说明),而对堆的操作也往往集中在堆顶。

通常题目所给我们的是一系列没有规则的数,这时我们需要对数组进行调整(以下以最大堆为例),此处还有最关键的区别就是通常我们所讲的建堆和优先队列是相同的,在C++中,我们通过STL函数即可直接建堆。

若不熟悉的话,有些头文件看起来很困难,但是网上多找点相关资料记住就好。

empty( )  //判断一个队列是否为空

pop( )  //删除队顶元素

push( )  //加入一个元素

size( )  //返回优先队列中拥有的元素个数

top( )  //返回优先队列的队顶元素


优先队列详解(转载)

priority_queue的解释

#include <iostream>
#include <queue>
#include <vector>
#include <string.h>
using namespace std;

int main()
{

       priority_queue<int,vector<int>,less<int> >Q;//最大优先队列
       

       //priority_queue<int,vector<int>,greater<int> >Q;//最小优先队列

       //priority_queue<int>Q;//默认为最大优先队列

       Q.push(5);
    Q.push(10);
    Q.push(6);
    Q.push(2);
    Q.push(4);
    Q.push(8);
    Q.push(11); //堆中元素为有序排列。
       while(!Q.empty())
       {
           cout << Q.top() << endl;
           Q.pop();
       } 
       return 0;
}

为方便理解,通过一道题来熟悉一下。大笑

The kth great number

原题

Time Limit : 2000/1000ms (Java/Other) Memory Limit :65768/65768K (Java/Other)
Total Submission(s) : 26 Accepted Submission(s) : 9

Problem Description
Xiao Ming and Xiao Bao are playing asimple Numbers game. In a round Xiao Ming can choose to write downa number, or ask Xiao Bao what the kth great number is. Because thenumber written by Xiao Ming is too much, Xiao Bao is feeling giddy.Now, try to help Xiao Bao.
Input
There are several test cases. For eachtest case, the first line of input contains two positive integer n,k. Then n lines follow. If Xiao Ming choose to write down a number,there will be an " I" followed by a number that Xiao Ming willwrite down. If Xiao Ming choose to ask Xiao Bao, there will be a"Q", then you need to output the kth great number.

Output
The output consists of one integerrepresenting the largest number of islands that all lie on oneline.

Sample Input
8 3

I  1

I  2

I  3

Q

I  5

Q

I  4

Q
Sample Output
1

2

3
提示
Xiao Ming won't ask Xiao Bao the kth great number when the numberof the written number is smaller than k.

(1=<k<=n<=1000000)

#include <iostream>
#include <queue>
#include <algorithm>
#include <vector>
using namespace std;

struct cmp
{
    bool operator()(int x, int y)
    {
          return x > y;//最小的优先级高
     }
};

int main()
{
    int  num; 
    while(~scanf("%d", &num))
    {
         int k;
         scanf("%d", &k);
         priority_queue<int, vector<int>, cmp> Q;
         for(int i = 0; i < num; i++)
         {
              char ch;
              cin >> ch;
              if(ch == 'I')
              {
                  int a;
                  cin >> a;
                  Q.push(a);
                  while(Q.size() > k)
                      Q.pop();
              }
              if(ch == 'Q')
                 cout << Q.top() << endl;
          }
          while(!Q.empty())
                Q.pop();
    }
}

大家谁还想试手的可以看看 这道题

这道题做到最后发现忘了计数,而且计数要求在最前面输出,当时就“哭了”。 大哭 大哭

下面是引用某大佬的解法;

 #include<stdio.h>  
    #include<string.h>  
    #include<functional>  
    #include<queue>  
    using namespace std;  
    typedef struct  
    {  
        char str[15];  
        int ans;  
    }Word;  
    Word s[1133333];  
    priority_queue<int, vector<int>, greater<int> > q;  
    int main(void)  
    {  
        int n, i, b, a, k;  
        char str[15];  
        scanf("%d", &n);  
        k = 0;  
        for(i=1;i<=n;i++)  
        {  
            scanf("%s", str);  
            if(str[0]=='i')  
            {  
                scanf("%d", &a);  
                s[++k].ans = a, strcpy(s[k].str, str);  
                q.push(a);  
            }  
            else if(str[0]=='r')  
            {  
                if(q.empty()!=0)  
                {  
                    s[++k].ans = 1, strcpy(s[k].str, "insert");  
                    q.push(1);  
                }  
                strcpy(s[++k].str, str);  
                q.pop();  
            }  
            else  
            {  
                scanf("%d", &a);  
                if(q.empty()!=0)  
                {  
                    q.push(a);  
                    s[++k].ans = a, strcpy(s[k].str, "insert");  
                }  
                b = q.top();  
                if(b>a)  
                {  
                    q.push(a);  
                    s[++k].ans = a, strcpy(s[k].str, "insert");  
                    b = a;  
                }  
                while(b<a)  
                {  
                    strcpy(s[++k].str, "removeMin");  
                    q.pop();  
                    if(q.empty()!=0)  
                    {  
                        q.push(a);  
                        s[++k].ans = a, strcpy(s[k].str, "insert");  
                        break;  
                    }  
                    b = q.top();  
                    if(b>a)  
                    {  
                        q.push(a);  
                        s[++k].ans = a, strcpy(s[k].str, "insert");  
                        b = a;  
                    }  
                }  
                s[++k].ans = a, strcpy(s[k].str, str);  
            }  
        }  
        printf("%d\n", k);  
        for(i=1;i<=k;i++)  
        {  
            if(s[i].str[0]=='r')  
                printf("%s\n", s[i].str);  
            else  
                printf("%s %d\n", s[i].str, s[i].ans);  
        }  
        return 0;  
    }  

这是我第一次写博客,如有错误的地方,欢迎大家留言。大笑害羞

### Python 中优先队列的概念及用法 #### 一、概念介绍 是一种特殊的树形数据结构,在大多数情况下,这种结构是一棵完全二叉树,并且满足特定性质:对于最大而言,父节点的键值总是大于等于子节点;而对于最小,则相反。在Python中,`heapq`模块提供了一个简易接口用于创建最小,这实际上就是一种高效的优先队列实现方式[^5]。 优先队列允许每个元素都有一个关联的优先级,当访问或者移除项目的时候,拥有最高优先级的项目会被最先处理。通过使用`heapq`模块中的函数可以在列表上轻松构建并维护这样的队列,从而实现了O(log n)时间复杂度下的插入和弹出操作效率[^4]。 #### 二、基本操作演示 下面给出了一些常见的基于`heapq`的操作实例: - **初始化空** ```python import heapq as hq min_heap = [] # 创建一个新的最小 hq.heapify(min_heap) # 将列表转换成,默认是最小 ``` - **向中加入新项** ```python item_to_add = (priority_value, task_description) hq.heappush(min_heap, item_to_add) ``` 这里需要注意的是,如果要存储的对象不是简单的数值而是元组形式的话,那么比较将会依据第一个元素来进行排序,即这里的`priority_value`决定了项目的顺序[^1]。 - **获取并移除最小/大项** ```python smallest_item = hq.heappop(min_heap) # 返回并删除最小项 ``` 此过程同样保持了剩余部分仍然是有效的结构。 - **替换顶元素而不改变其他任何东西** ```python new_smallest = hq.heapreplace(min_heap, new_item) ``` 该命令相当于连续执行了一次heappop()紧接着一次heappush()[^1]。 #### 三、自定义类作为成员 有时候可能希望把更复杂的对象放入到里边去,比如股票交易记录等。这时可以通过定义自己的类来表示这些实体,并重载其小于运算符以便于正确地按照所需属性进行排序[^3]。 ```python class StockRecord: def __init__(self, ticker, price, share): self.ticker = ticker self.price = price self.share = share def __lt__(self, other): return self.price * self.share < other.price * other.share record_a = StockRecord('AAPL', 150.78, 100) record_b = StockRecord('GOOG', 2900.45, 5) stock_min_heap = [] hq.heappush(stock_min_heap, record_a) hq.heappush(stock_min_heap, record_b) ``` 上述代码片段展示了如何创建一个包含两个不同公司股票信息的最小,其中每条记录都由价格乘以股份数量决定其相对位置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值