关于C++的权值优先队列的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于C++的权值优先队列的问题相关的知识,希望对你有一定的参考价值。

struct NodeWeightBig //权值最大优先队列结构体

friend bool operator< (NodeWeightBig n1,NodeWeightBig n2)

return n1.weight< n2.weight;//为什么这样就可以比较权值????

int value;//数值
int weight;//权值
;
此处的
friend bool operator< (NodeWeightBig n1,NodeWeightBig n2)

return n1.weight< n2.weight;

如何理解?
为什么有这段代码就可以实现权值最大优先出队?
friend的作用似乎是友元函数,但是为什么要使用友元?
这里并没有类,更加没有私有成员。
请详细解释这段代码的作用,谢谢O(∩_∩)O~

在C++中struct的作用跟class几乎一样,唯一不同的是在struct中的字段默认是public类型的,而在class中默认是private的。
好了,回到这个问题,把一个方法定义问友元,实际上破坏了class的封装性,但是提供了在类外访问类内部元素的一个方法,实际上友元函数并不属于这个类。
就上面那段代码而言,struct NodeWeightBig可以看做是NodeWeightBig类,它重载了<运算符,NodeWeightBig类的对象间就可以通过调用<重载函数来进行比较。
如果把这个类给某个容器,而这个容器恰好有某种排序功能,而且约定了要提供一个<重载方法,给它调用,然后通过这个方法进行权值比较,最终得出一个按权值排列的序列也比较好理解了。

希望对你有帮助。追问

priority_queue是本身具有比较方法的,默认是按数值大小排序。那么 问题中的那个友元函数是如何重载比较方法的?n1、n2的值是什么。既然友元函数不属于类,他又是在哪里起作用的?

追答

priority_queue的模板声明带有三个参数,priority_queue
Type 为数据类型, Container 为保存数据的容器,Functional 为元素比较方式。

三个参数中,最后两个是可省略的。而STL里面容器默认用的是 vector. 比较方式默认用 operator< , 所以如果你把后面俩个参数 缺省的话,优先队列就是大顶堆,队头元素最大。

我想你说的“priority_queue是本身具有比较方法” 应该是指:operator < 。 实际上你把priority_queue中用来比较元素优先级的函数operator < ,给重载了,所以就实现了你想要的效果。而不是默认的operator <。

现在我们看看友元函数,友元函数不属于任何一个类,但是她跟某个类又是friend关系(可以访问这个对象,注意是对象而不是类,中的所有字段),除此之外,她和普通函数几乎一样。

看个简单的例子:
class A
int a;
friend bool operator< (A n1,A n2)

A a1, a2;
a1 < a2;
a2 < a1;
上面的两个式子实际上调用的都是friend bool operator< (A n1,A n2);如果把friend关键字去掉,第一个式子调用的是a1对象的 bool operator< (A n1,A n2)函数,第二个调用的是 a2对象的bool operator< (A n1,A n2)函数。

希望对你有帮助。

追问

如果把friend去掉不是只能存在一个参数了?
其实还是没有弄懂呢,类A创建了对象a1、a2;但是为什么a1<a2后 ,又有a2<a1了?
谁充当了n1,谁又是n2?
话说你的bool函数没有返回值呢。返回值的真假又有什么作用?

追答

没想到楼主这么较真,会纠结于这个例子的细节。

friend.h

#ifndef _FRIEND_
#define _FRIEND_
#include <iostream>
class A

public:
A() 
a = 0; 
;
A( int a_, char obj_name_ )
a = a_; 
obj_name = obj_name_;
;
bool operator< (const A a1)
std::cout << "object name: " << obj_name << std::endl;
return a < a1.a;
;
private:
int a;
char obj_name;
;
#endif

main.cpp

#include "friend.h"
int main()
A a1(1, '1'), a2(2, '2');
std::cout << (a1 < a2) << std::endl;
std::cout << (a2 < a1) << std::endl;
return 0;

其实我只是想通过这个列子说明成员函数和友元函数的区别,他俩的关键区别在于成员函数中可以使用this指针,而在友元函数中不能使用这个指针。

一般用友元函数而不用成员函数的原因,是因为两个操作数的类型不同,这里因为你在operator<函数中直接访问各个对象的私有成员,在成员函数里这么写是不能实现的。当然提供一个get方法获取私有成员的值,将operator<重写为成员函数也未为不可。


写了这么多,我有点想,把所有的回答都删掉的冲动。

其实我们上百度知道的原因很简单,就是为了获取知识,让学习的过程变得更有趣一点,当然如果能帮到别人也是一件很让人开心的事。。。


好吧,我想说的,就这些。

参考技术A 我想楼主是想用c++ stl的priority_queue<T>
priority_queue<T> 是一个模板类,其用最大堆实现了一下优先队列
由于维持堆序需要比较操作,要求类T必须了<运算符
bool operator< (NodeWeightBig n1,NodeWeightBig n2) 就是在重载 < 用于两个 NodeWeightBig 对象的比较, 具体的比较方法为判断谁的权更大
由于你用的是struct 没有private元素 不定义为友元也可以 即以下写法可以:

struct NodeWeightBig //权值最大优先队列结构体

int value;//数值
int weight;//权值
;
bool operator< (NodeWeightBig n1,NodeWeightBig n2)

return n1.weight< n2.weight;//为什么这样就可以比较权值????

若在类内重载<若不加friend 则参数只能有一个即

struct NodeWeightBig //权值最大优先队列结构体

int value;//数值
int weight;//权值
bool operator < (const NodeWeightBig& a) const
return weight < a.weight;

;追问

确实是STL中的priority_queue呢,但是没有完全弄懂。我只是用了别人使用priority_queue的方法来设计自己的程序而已。friend可以增加一个参数的解释让我茅舍顿开,确实去掉friend之后,编译器就报错说bool operator的参数太多了。其实,我想知道friend bool operator 的两个参数是从哪里传递过来的?这个函数不属于结构体,又在哪里起作用呢?

cf 1243 D. 0-1 MST(队列瞎搞)

题意:

有n个点的无向完全图,有m条边的边权为1,其余都为0,求最小生成树的权值。

 

思路:

初始时,生成树的大小为0,先把点1加入进去,然后把那种不需要花费权值,就可以加入的点,先加入进去,

因为每加入一些点,就会有一些点,从需要花费权值 转变为 不需要花费权值,所以要优先加入这样的点。

怎么判断这个点加入需不需要花费权值,

每次加入一个点的时候,就把与这个点相连的点加1,如果这个点的值,等于生成树的大小,那么就说明它与生成树中所有的点都相连,所以它需要花费权值。

如果未在生成树中的所有点的值,都等于生成树大小了,那就随便加入一个点,那就很可能会再解锁一些点。

就这样循环搞,直到所有点都加入生成树了为止。

用队列实现。

 

这样的复杂度不好算,于是,假设最糟糕的情况(或许有更糟糕的,但是我想不到了)

有1000个点,1e6条边的权值都为1(题目的m最大才1e5,不过没关系,稍微糟糕一点)

那么就意味着,每次遍历完点都没有发现可以无花费就加入的点,那也就n2 级别的复杂度,可以过。

(为什么这样的题我要写这么多字啊。。。)

 

代码

技术图片
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
vector<int>mp[maxn];
int qu[maxn*10];
int n,m,num[maxn];
int main(){
    while(scanf("%d%d",&n,&m) != EOF){
        int u,v,now = 0;
        for(int i = 1;i <= n;i++)
            mp[i].clear();
        memset(num,0,sizeof(num));
        for(int i = 1;i <= m;i++){
            scanf("%d%d",&u,&v);
            mp[u].push_back(v);
            mp[v].push_back(u);
        }

        now = 1;
        for(int i = 0;i < mp[1].size();i++){
            v = mp[1][i];
            num[v] = 1;
        }

        int ans = 0,l = 0,r = 0,_l,_r,flag;
        for(int i = 2;i <= n;i++)
            qu[r++] = i;
        flag = 0;
        while(l < r){
            _r = r;
            flag = 0;
            while(l < _r){
                u = qu[l++];
                if(num[u] < now){
                    flag = 1;
                    now++;
                    for(int j = 0;j < mp[u].size();j++){
                        v = mp[u][j];
                        num[v]++;
                    }
                }
                else{
                    qu[r++] = u;
                }
            }
            if(!flag){
                ans++;
                now++;
                u = qu[l++];
                for(int i = 0;i < mp[u].size();i++){
                    v = mp[u][i];
                    num[v]++;
                }
            }
        }
        printf("%d
",ans);
    }
    return 0;
}
View Code

 

以上是关于关于C++的权值优先队列的问题的主要内容,如果未能解决你的问题,请参考以下文章

堆(优先队列)求huffman WPL

uva 10954Add All(算法效率+Huffman编码+优先队列)

Java Collection - PriorityQueue 优先队列

luogu1484 种树 (优先队列)

堆....

关于css的优先级