在 C++ 中使用邻接表的图

Posted

技术标签:

【中文标题】在 C++ 中使用邻接表的图【英文标题】:Graphs using Adjacency List in c++ 【发布时间】:2013-07-29 14:01:04 【问题描述】:

我正在尝试用 C++ 实现一个图形。我使用包含两个变量的结构来表示图中的节点 - a) 一个包含有关节点的一些信息的整数。 b) 一个列表,其中包含与其相连的其他顶点的索引。 以下是代码。

// Graphs using adjacency list

#include <iostream>
#include <list>
#include <cstdlib>
using namespace std;

// structure to represent a vertex(node) in a graph
typedef struct vertex
    int info;
    list<int> adj;   // adjacency list of edges contains the indexes to vertex
 *vPtr;             

int main()
    vPtr node = (vPtr)malloc(sizeof(struct vertex));
    node->info = 34;            // some arbitrary value
    (node->adj).push_back(2);   // trying to insert a value in the list
    return 0;

代码编译正常,但在我推回列表中的一个元素时出现运行时错误。我的结构有什么问题吗? 我正在使用代码块和 GNU GCC、C++ 98 编译器来编译我的代码。

【问题讨论】:

vPtr 声明有些可疑。 @Jim :我不这么认为,因为代码只有在我推回列表时才会出现问题。如果我删除该行,那么代码就可以正常工作。 【参考方案1】:

malloc 是一个 C 函数 - 它不应该与 C++ 对象一起使用,which is very well explained here (简短回答:在 C++ 中,当你不处理 POD 类型时,std::list 在你的在这种情况下,您必须调用对象的构造函数才能使实际对象准备好使用,而malloc() 不会这样做。

You should used new instead。虽然malloc 只分配一块大小为vertex 的内存块,但new 这样做并且还通过调用它的构造函数来初始化std::list(有趣的是,当你调用delete() 时,你正在调用你的对象的析构函数)。

这里有一段代码适用于您的情况,但我建议您开始在 C++ 项目中使用更多 C++ 功能:

#include <iostream>
#include <list>
#include <cstdlib>
#include <new>

using namespace std;

// structure to represent a vertex(node) in a graph
typedef struct vertex
    int info;
    list<int> adj;   // adjacency list of edges contains the indexes to vertex
 *vPtr;             

int main()
    cout << "allocating memory for our vertex struct... \n";
    vPtr node = new vertex();
    node->info = 34;            // some arbitrary value
    (node->adj).push_back(2);   // trying to insert a value in the list
    cout << "cleaning allocated memory... \n";
    delete(node);

    return 0;

【讨论】:

嗯,确实它强烈地改变了代码。但我认为这是必要的,因为问题的性质是使用了错误的工具来完成这项工作。 我完全同意。但这是一个有趣的学术练习,可以了解 malloc 和 STL 如何交互(或不交互)。关于 malloc 不运行构造的见解很有趣。 是的,我认为你有更好的答案,因为它解决了这个问题。 Streppel绕过了它,这可能是正确的做法,但没有解释事情。我会 +1 你的答案,至少我能做到.... @Jim,是不是 malloc 不做 stl 对象所需的东西? 我认为 STL 可以做任何事情,但是一些熟悉不同方法的人有时想混合使用它们。一般来说,这可能不是最好的做法,但它确实发生了。【参考方案2】:

几件事。

    因为您使用的是malloc,所以从未调用过constructor,并且作为 这样的非原始成员 adj 永远不会被构造并且是 空。

    您正在泄漏内存,因为您从未释放/删除任何动态分配的内存。

    如果您使用 C++,为什么要使用 malloc 而不是 newdelete

    对于 C++,您不必在 sizeof 中说 struct vertex。

要修复它,你可以这样做:

vPtr node = new struct vertex(); // also change to delete instead of free

// use current malloc line, change adj to be a pointer to a list and new it
// but this will cause additional problems for you since you really need to use a constructor for STL::list
node->adj = new list<int>;

你真的不应该在这里使用malloc

【讨论】:

也许他不应该,但很高兴知道(无论如何)这些是如何相互作用的。 我不认为 node->adj = new list;编译。 糟糕,确实如此,当您将 adj 设为 ptr 时。 是的,这正是我在评论中所说的你必须做的:-) @Jim 别担心,伙计!干杯并感谢您的投票!这很适合我的第一个帖子答案是正确的永远不会得到爱:-p 找到了一些你的好帖子,我也艰难地通过了。这很有趣,但您偶尔会遇到必须将两者混合在一起的情况,特别是如果您还不能使用placement-new并且出于其他性能原因必须将它们混合在一起(调用new和malloc对延迟不利) .. 是的,我意识到 STL 也是如此..【参考方案3】:

这是 UpAndAdam 的回答,写得很完整。

// Graphs using adjacency list
//
#include <iostream>
#include <list>
#include <cstdlib>
using namespace std;

// structure to represent a vertex(node) in a graph
typedef struct vertex
    int info;
    list<int> *adj;   // adjacency list of edges contains the indexes to vertex
 *vPtr;             

int main()
    vPtr node = (vPtr)malloc(sizeof(struct vertex));
    node->adj = new list<int>;
    node->info = 34;            // some arbitrary value
    (node->adj)->push_back(2);  // trying to insert a value in the list
    return 0;

【讨论】:

以上是关于在 C++ 中使用邻接表的图的主要内容,如果未能解决你的问题,请参考以下文章

对于 C++ 中的图问题,邻接列表或邻接矩阵哪个更好?

采用邻接表存储的图的深度优先遍历算法类似于二叉树的先序遍历,为啥是先序呢?

无权无向图,用邻接表存储,求各个顶点之间的最小边数,求c++或c代码。十分感谢啊

C++ class实现邻接表存储的图(完整代码)

图的邻接矩阵存储

使用具有两个链表的邻接表的深度优先搜索 C++ 实现