Dijkstra算法中的优先级队列

时间:2013-07-27 13:29:35

标签: c++ algorithm dijkstra

这是我对Dijkstra算法的代码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>

#define pp pair<int,int>
using namespace std;
struct pri
{
    int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
    {
        return p1.second<p2.second;
    }
}p;
int main()
{
    priority_queue<pp,vector<pp>,pri> q;
    int n;
    cin>>n;
    vector<pp> g[n+1];
    int e,u,v,w,i;
    cin>>e;
    for(i=0;i<e;i++)
    {
        cin>>u>>v>>w;
        g[u].push_back(pp(v,w));
        g[v].push_back(pp(u,w));
    }
    int s;
    cin>>s;
    int d[n+1];
    for(i=1;i<=n;i++)
        d[i]=999;
    d[s]=0;
    q.push(pp(s,d[s]));
    while(!q.empty())
    {
        u=q.top().first;
        q.pop();
        int size=g[u].size();
        for(int i=0;i<size;i++)
        {
            v=g[u][i].first;
            w=g[u][i].second;
            cout<<u<<" "<<" "<<w<<endl;
            if(d[v]>d[u]+w)
            {
                d[v]=d[u]+w;
                q.push(pp(v,d[v]));
            }
        }
    }
    for(i=1;i<=n;i++)
        printf("node %d,min weight=%d\n",i,d[i]);
    return 0;
}

在此,我无法理解

的工作原理
 priority_queue<pp,vector<pp>,pri> q;

这与:

有关
struct pri
{
    int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
    {
        return p1.second<p2.second;
    }
}p;

()运算符在此中的用途是什么?我的意思是它在这段代码中的功能如何?

另外,为什么我们在&中使用operator()

此外,此比较器如何在优先级队列定义中工作? 为什么我们在运算符定义中使用常量?

我的意思是说在运算符工作中这种比较究竟如何,我们不能使用任何比较 其他符号为= * @或任何其他符号而不是()

6 个答案:

答案 0 :(得分:2)

struct pri {
    int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
    {
        return p1.second<p2.second;
    }
}p;

通过重载()运算符

来创建function object

这将作为比较类

传递给priority_queue

&用于将pair作为常量引用传递,确保不会复制实际参数(通过将它们作为引用传递),同时函数无法修改他们的价值(使用const关键字)

使用此函数对象,队列确定如何插入值(对)。

在这种情况下,pair的第二个值用于比较。

答案 1 :(得分:2)

我认为你写的比较函数是错误的。

int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
{
    return p1.second<p2.second;
}

正确的应该是

int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
{
    return p1.second>p2.second;
}

因为在priority_queque中你可以找到表达式comp(a,b),其中comp是这种类型的对象而a和b是容器中的元素,如果a被认为是,则返回true在b之前,在函数定义的严格弱序中。

因为在Dijkstra算法中,值较小的节点应该具有更高的优先级,因此我们在这里使用的运算符应该是

p1.second>p2.second

(通过使用您的代码解决问题,我花了很长时间才弄清楚这个问题,我的程序的结果总是与正确的结果不同。) (顺便说一句,在Dijkstra算法本身中,我认为一旦节点弹出为最小节点,就不需要再次弹出它并更新连接到它的所有节点。这可以节省大量时间。)

答案 2 :(得分:1)

当声明变量(包括函数参数)时,&将变量标记为引用。对某些类型的参数使用引用是非常基本和常见的,部分原因是它在不创建副本的情况下传递参数(对于例如std::vector非常有用)并且它还允许在函数中更改非const引用作为输出论证的一种形式。

至于在这样的结构中使用operator(),它会生成结构function objects的实例,换句话说,可以像函数一样调用对象。

答案 3 :(得分:1)

我认为你的问题是priority_queue<pp,vector<pp>,pri> q;行?

这声明了q类型的变量priority_queue<pp,vector<pp>,pri>priority_queue定义为

template<class T,
         class Container = vector<T>,
         class Compare = less<typename Container::value_type> >
class priority_queue;

因此,pp是元素的类型,vector<pp>是容器(与默认值相同),pri是一个函数对象,用于比较中的项目队列(Compare)。 priority_queue使用Compare来排序其元素。如果元素无法直接比较,或者默认值不合适,那么您可以提供自己的元素。在这种情况下,元素将按每个元素second中的pair成员排序。

答案 4 :(得分:0)

基本上与其他答案相同,只是更详细一点 - operator()代码定义了优先级队列应如何进行比较以确定队列中的项目优先级。使用这种类型的框架,您可以定义一个优先级队列来存储任何类型的对象,并且可以根据您在对象上所需的任何类型的自定义顺序对优先级队列进行排序。

答案 5 :(得分:0)

我重构了这段代码并用hackerrank检查了它。

#include <cstdio>
#include <vector>
#include <queue>
#include <iostream>
#include <vector>
#include <deque>
#include <set>
#include <limits>
#include <iterator>
#include <algorithm>
#include <functional>

using namespace std;

struct pri
{
    typedef pair<int,int> pp;
    typedef deque<pri::pp > list;
    typedef vector< pri::list > graph;
    int operator() (pp&p1,const pp&p2)
    {
        return p1.second>p2.second;
    }
    typedef priority_queue< pri::pp, pri::list, pri > queue;
};

static int f1(const int x){ return x==std::numeric_limits<int>().max()?-1:x; }

int main()
{
    int t;
    cin>>t;
    while(t--){
        int n,e;
        cin>>n>>e;
        pri::graph g(n+1);
        for(int i(0);i<e;i++){
            int u,v,w;
            cin>>u>>v>>w;
            g[u].push_back(pri::pp(v,w));
            g[v].push_back(pri::pp(u,w));
        }
        vector<int> d(n+1,std::numeric_limits<int>().max());
        int s;        cin>>s;
        d[s]=0;
        pri::queue q;
        q.push(pri::pp(s,d[s]));
        set<int> vs;
        while(!q.empty()) {
            const int u(q.top().first);
            const pri::list& gu(g[u]);
            q.pop();
            vs.insert(u);
            for( pri::list::const_iterator i(gu.begin()); i != gu.end(); ++i ) {
                const int v(i->first),  w(i->second);
                if( vs.find(v)==vs.end() ){
//                  cout<<u<<" "<<v<<" "<<w<<endl;
                    if( d[v]>d[u]+w ) {
                        d[v]=d[u]+w;
                        q.push(pri::pp(v,d[v]));
                    }
                }
            }
        }
        copy_if(d.begin()+1,d.end(),d.begin(),std::bind2nd(std::not_equal_to<int>(),0));
        transform(d.begin(),d.end()-2,ostream_iterator<int>(cout," "),f1);
        cout<<endl;
    }
    return 0;
}