堆与优先队列

堆与优先队列

(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;  
    }  

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值