////编辑#2:删除了所有以前的信息,现在只发布工作代码。以前的问题变得过于冗长:
#include <iostream>
#include <vector>
using namespace std;
template<class T>
class Node{
T data;
vector<Node<T>*> adjacent;
friend class Graph;
public:
int n;
Node(T initData) : data(initData), n(0){}
void addAdjacent(Node<T>& other){
adjacent.push_back(&other);
n++;
}
T getData(){
return data;
}
Node<T>* getEdge(int edgeNum){
return adjacent[edgeNum];
}
};
template<class T>
class GraphCl{
int n;
vector<Node<T>*> nodes;
T input;
public:
GraphCl(int size): n(size){
for (int i=0;i<n;i++){
cout << "Enter data for node " << i << ": ";
cin >> input;
nodes.push_back(new Node<T>(input)) ;
}
}
void addEdge(int baseNode, int edgeNode){
nodes[baseNode]->addAdjacent(*nodes[edgeNode]);
}
void printGraph(){
for (int i=0;i<n;i++){
Node<T> *base = nodes[i];
cout << "Data of node " << i <<": "<< base->getData() <<endl;
for (int j=0;j<base->n;j++){
cout << "Edge #"<< j+1 << " of node " << i << ": " << base->getEdge(j) <<endl;
}
}
}
};
int main(){
GraphCl<int> *myGraph = new GraphCl<int>(5);
myGraph->addEdge(0,1);
myGraph->addEdge(0,2);
myGraph->addEdge(0,3);
myGraph->addEdge(0,4);
myGraph->addEdge(3,1);
myGraph->addEdge(3,0);
myGraph->printGraph();
return 0;
}
输出:
Enter data for node 0: -34
Enter data for node 1: 12
Enter data for node 2: 56
Enter data for node 3: 3
Enter data for node 4: 23
Data of node 0: -34
Edge #1 of node 0: 0x7fbeebd00040
Edge #2 of node 0: 0x7fbeebd00080
Edge #3 of node 0: 0x7fbeebe00000
Edge #4 of node 0: 0x7fbeebd000d0
Data of node 1: 12
Data of node 2: 56
Data of node 3: 3
Edge #1 of node 3: 0x7fbeebd00040
Edge #2 of node 3: 0x7fbeebd00000
Data of node 4: 23
正如您所看到的,这个简单的实现正在发挥作用。我决定删除所有复杂的东西,并通过动态变化的向量保持简单。显然效率较低,但我可以从这里开始工作。由于我是C ++的新手,之前的实现只是让我的头脑旋转360度,思考所有指向指针的位置,甚至没有考虑内存分配。上面的代码基本上是一个对输入错误非常敏感的有向图,所以我还是继续研究它。 谢谢你的帮助!
答案 0 :(得分:1)
<强>辅助强>
关于数组对Graph
的可访问性,与当前实现最接近的是将Graph
声明为Node
的朋友。只需添加:
friend Graph;
到Node
类声明的末尾。
也就是说,将课程设为friend
有时候表明,如果课程需要对彼此了解太多,那么您定义的API并不完全正确。&#39;实施细节。您也可以为Node
提供界面,例如:
void AddAdjacent(Node* other);
管理相邻节点
如果您希望adjacent
指针数组可以增长,那么您基本上是在重新创建std::vector
,因此我建议您使用std::vector<Node*>
。使用默认(空)构造函数初始化向量会处理它,nodes[baseNode]->adjacent.push_back(...)
中只需要addEdges
。
如果内存不是考虑因素,并且图中有最大数量的节点,则可以实例化一个恒定大小的数组。
如果你真的不想使用std::vector
,但实际上你想要一个可增长的指针数组,那么你必须管理自己的malloc
和{{1调用。我会写一些相关的东西,但我的建议是继续free
。
如果你很好奇,数组方法看起来像:
vector
插入:
template<class T>
class Node : public Graph{
Node **adjacent; //pointer to array of POINTERS TO adjacent Nodes
int n;
size_t capacity;
T data;
friend Graph;
public:
Node(T initData) : data(initData), capacity(8) {
n = 0;
adjacent = reinterpret_cast<Node**>(malloc(capacity * sizeof(Node**)));
}
~Node() {
free(adjacent);
}
void Grow() {
size_t new_cap = base.capacity * 2;
Node<int> **copy = reinterpret_cast<Node<int>**>(malloc(new_cap * sizeof(Node**)));
memcpy(copy, base.adjacent, base.capacity); // copy and adjacent are non-overlapping, we can use memcpy
free(base.adjacent);
base.adjacent = copy;
base.capacity = new_cap;
}
};
答案 1 :(得分:0)
回答更新的问题
将Node
直接放在std::vector
的情况下,存在一些问题。
使用std::vector
对很多事情都很有用,但如果你这样做,你应该确保不要指向矢量。请记住,指针指的是存储对象存储位置的确切地址。 vector
是一个可增长的元素容器。为了连续存储元素,向量分配一堆内存,将对象放在那里,如果必须增长,它将分配更多内存并移动对象。它本质上是在做Node
中你正在做的事情并且增长(除非在它的情况下,它在释放旧内存之前明确地销毁了对象)。
请注意,您的Grow
函数会分配新内存并复制指针。同时,矢量可以分配新内存并复制数据。这意味着保持指向向量中数据的指针是不好的。 vector
给你的唯一保证是它的数据将继续使用数组样式的索引,查找,迭代等来访问,而不是数据将永远存在于同一个内存位置强>
解释您看到的确切错误
向量正在调用copy constructor。默认的复制构造函数逐个复制每个字段。在Node
的情况下,这不是您想要的,因为那时您有两个向量认为它们拥有Node** adjacent
内存位置。当第一个节点(旧副本)被销毁时,它将释放其相邻节点(与副本的相邻节点相同)。当新副本被销毁时,它将尝试释放相同的内存位置,但它已被释放。你在这里也有一个问题,如果你试图在第一个节点中销毁内存之后访问内存,你就会遇到麻烦。
当您只添加节点时,为什么会出现此错误?
当矢量增长到一定量时,需要调整大小。在大多数实现中,过程大致如下:
由于步骤2和3,您的错误正在显现。
修复此特定错误
对于您的情况,默认的复制构造函数并不好,因为复制节点应该符合所有数据的深副本。 C ++中的常规副本将复制类或结构本身的所有数据。如果数据是指针,则复制指针,而不是指向它的东西。
覆盖复制构造函数和赋值运算符:
Node(const Node<T>& other) : data(other.data), capacity(other.capacity), n(other.n) {
adjacent = reinterpret_cast<Node**>(malloc(capacity * sizeof(Node**)));
memcpy(adjacent, other.adjacent, capacity * sizeof(Node**));
}
Node<T>& operator= (const Node<T>& other) {
data = other.data;
capacity = other.capacity;
n = other.n;
adjacent = reinterpret_cast<Node**>(malloc(capacity * sizeof(Node**)));
memcpy(adjacent, other.adjacent, capacity * sizeof(Node**));
}
更大的问题
代码的一个更大问题是使用std::vector
和指向其元素的指针。选择以下之一: