Prim的算法C ++

时间:2014-05-11 02:54:47

标签: c++ algorithm graph

我在C ++中实现了一个简单版本的Prim算法,并且在将算法转换为基本的图形实现时遇到了一些困难。

我有一个边缘结构,如下所示:

struct edge 
{
    int src;
    int dest;
    int weight;
};

我只是将边缘推到图类中的向量。我不确定这是否是实现Prim的最佳方式,但它似乎对我的最终结果是最佳的,它能够简单地打印出顶点的数量visitTed和最小的总重量生成树。

我想我理解Prim的基本思想,但我对几点有疑问。我要求的只是推动正确的方向。特定于我的使用的伪代码是理想的。

1)选择一个起始顶点

2)在从源顶点到所有其他循环的while循环中,将边权重添加到某种堆中(这对我来说很困惑,有些算法会说初始化为无穷大但STL优先级队列没有有储备方法......)

3)获得最低边缘(从优先级队列弹出或在我考虑不周的实现中遍历向量以获得最低值...)

4)如果访问了最低值的目的地,则抛弃该边缘并尝试下一个。如果没有,请将边缘添加到最小生成树并将其标记为已访问。

我没有太多代码,而且我的收益正在减少,所以任何建议都值得赞赏。这就是我得到的:

vector<edge> graph::prims(int source, vector<edge> vt)
{
    int current;
    vector<bool> visited(numVert, false);
    vector<unsigned int> minWeight;
    minWeight.reserve(numVert);

    // Intilize minWeight to a large number
    for(int j=0; j < numEdges; j++)
    {
        minWeight[j] = 0xffffffff;
    }

    current = source; 

    // Will this even work? What if I pick the nth node...
    while (current <= numEdges)
    {
        // This should add the edge weights to the current vertex 
        // to a vector so the minimum can be found
        for(int i = 0; i < numVert; i++)
        {
            if(vt[i].src == current && visted[i] == false)
            {
                minWeight.push_back(vt[i].weight);
            }
        }
    }

    // Need to finish Prim's


    return vt;
}

我一直在尝试从互联网上获取代码并整天修改,这让我无处可去。所以我最终决定自己尝试一下。它并不多,但这花了我两个小时......

我的代码可以在Google Drive找到。

2 个答案:

答案 0 :(得分:2)

我查看了您的代码,看起来您的设计在某些方面并不完整。我们来看看。

您的graph课程如下:

class graph {
public:
        ... function prototypes ...
private:
        int numVert;
        int numEdges;
};

此类声明缺少一些相当重要的信息:特别是,在存储顶点数和边数时,不会存储有关属于给定graph实例的顶点或边的信息。

您已经拥有edgecity结构,可分别用于边和顶点。这些可以存储在std::vector<...>类的graph成员中,并且 - 如果您小心保留相关的排序 - 您可以通过数字索引解决这些问题,并且(大部分)都可以。完成后,您可以调整addEdgeaddCity,以便他们实际执行应有的操作 - 也就是说,分别向graph实例添加边或顶点

要考虑的另一件事是你真正想要存储你的边缘。 “最佳”方法取决于问题的性质,但对于大多数应用程序来说,将边缘存储在由顶点ID(例如std::map<std::vector<...> >实例)键入的结构中,或者作为每个顶点对象中的子字段就足够了(例如,通过向std::vector<...>类添加city成员字段。


除此之外,让我们来解决您尝试实施的实际算法。

Prim的算法,其核心是迭代应用此规则:

向候选最小生成树添加最小权重边缘,将树内部的某些顶点连接到外部的某个顶点。

也就是说,在每一步,我们都这样做:

  • 考虑到目前为止我们已经构建的树中的顶点;调用此集合A.(最初,这是您选择的单个顶点。最后,这是包含初始顶点的连通组件的顶点集;如果图形已连接,则这是所有顶点。 )
  • 考虑图中不在树中的顶点;叫这套B。
  • 查看将集合A中的任何顶点与集合B中的任何顶点连接的所有可能边(图论理论语言中的切割集(A,B))。如果没有,你就完成了。否则,选择权重最小的边缘并将其添加到树中。

您可以证明,在连接原始图形的情况下,此算法会生成具有最小总边缘权重的生成树。试着为自己证明这一点。


那么,你现在在哪里?虽然我无法理解你的想法,但我可以告诉你代码告诉我的内容:

  • 您正在尝试跟踪您已访问过的顶点集。
    • 这很好;你需要那个。
  • 您正在尝试跟踪剪辑集,即退出访问集的边缘。
    • 你也需要这个。
    • 我不确定为什么你只使用std::vector<unsigned int>来达到这个目的,因为对于给定的边缘,你需要跟踪三个量:'from'顶点,'to'顶点,以及重量。您可能需要std::vector<edge>来代替此目的。
  • 看起来你正试图填充这一套。
    • 您可能需要重做此位,具体取决于您是否更改了数据结构的布局。
    • 主要想法 - 找到从被访问节点运行到未访问节点的边缘 - 是的,但我不确定当前代码建议的方法是否会起作用。

那么,算法中缺少什么?

  • 一旦你有一个有效的剪辑集,你需要找到权重最低的集合中的边缘。
  • 您需要将此边添加到返回集。
  • 您需要将此边连接的顶点标记为已访问。将此节点称为N。
  • 您需要更新剪辑集。特别是,需要删除将N连接到先前访问过的顶点的任何边,并且需要添加将N连接到某些未访问顶点的任何边。

我希望这会帮助你。如果您对任何事情感到困惑,需要更多解释,或者认为我所说的内容不准确或不正确,请告诉我,我会更新此答案。

答案 1 :(得分:0)

//Prims Algorithm implementation using matrix in simpler way

#include<iostream>
#include<limits.h>
using namespace std;
int n=5;

//Min Node will return the node having minimum weight
int min_node(int matrix[5][5],bool visited[5]){
    int result;
    int min_value=INT_MAX;

    for(int i=0;i<n;i++){
        if(visited[i]){
            for(int j=0;j<n;j++){
                if(matrix[i][j]<min_value && !visited[j]){//If the node is not in visited array then consider it,otherwise not,
                                                            //to avoid the loop in the minimum spanning tree
                    min_value=matrix[i][j];//update the min value
                    result=i*10 + j;
                }//endl inner if structure
            }//end inner for loop
        }//end outer if structure
    }//end outer for loop

    return result;
}

int main(){
cout<<"Hello world\n";
int matrix[5][5]={
                    {0,18,15,0,0},
                    {18,0,12,0,13},
                    {15,12,0,20,0},
                    {0,0,20,0,11},
                    {0,13,0,11,0}
                };

//Display the matrix
for(int i=0;i<n;i++){
    for(int j=0;j<n;j++)
        cout<<matrix[i][j]<<"\t";
     cout<<"\n";
}

//Make the disconnected node weight = MAX
for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
        if(matrix[i][j]==0)
            matrix[i][j]=INT_MAX;
    }
}

//Take an visited array
bool visited[5];
//Make all the entries of visited array false
for(int i=0;i<5;i++)
    visited[i]=false;

int source;
cout<<"Enter the source vertex\n";
cin>>source;

visited[source]=true;

//Tree having 'n' vertices will have 'n-1' edges in the minimum spanning tree
int t=4;
while(t>0){
    int result=min_node(matrix,visited);
    int i=result/10;
    int j=result%10;
    visited[j]=true;//Now add the new node the visited, to consider the its edeges in the condition
    cout<<"Path "<<i<<"- "<<j<<" ="<<matrix[i][j]<<endl;

t--;
}

return 0;
}