假设我有从N
到0
标记的N-1
个顶点。每个顶点最多有3
个邻居,至少有1
个邻居。假设邻居信息最初存储在名为pairs
的向量中,其中pairs[2*i]
和pairs[2*i+1]
是一对相邻的顶点。
现在我需要快速查看邻居对vertex[i]
的看法,存储此信息的最佳方式是什么?
我提出的方法是:
声明一个名为neighbors[3*N]
的向量,以便neighbors[3*i+0]
neighbors[3*i+1]
和neighbors[3*i+2]
存储三个可能的邻居。
为什么说可能,因为每个顶点最多有三个邻居。
所以我将向量neighbors
的所有元素初始化为N
,这意味着它不是有效的邻居,因为顶点标记为0
到{{1 }}
代码实现如下:
N-1
我对我的方法感到不舒服的事情:
声明向量void get_neighbors(const std::vector<int>& pairs,
std::vector<int>& neighbors) {
int N = neighbors.size()/3;
int M = pairs.size()/2;
//init all the vertexes' neighbours to nothing
for (int i=0; i<3*N; ++i) {
neighbors[i] = N;
}
//loop through all the vertexes, and store their neighbors
for(int i=0; i<N; ++i) {
int j = 0;
//loop through pairs, and find out what neighbors vertex[i] has
for (int k=0; k < M; ++k) {
if(pairs[2*k]==i) {
neighbors[3*i+j]=pairs[2*k+1];
++j;
}
else if(pairs[2*k+1]==i) {
neighbors[3*i+j]=pairs[2*k];
++j;
}
}
}
}
太多了,因为它的许多元素都是无用的neighbors(3*N)
。
如果我想查找N
的邻居,每次我需要测试vertex[i]
,neighbors[3*i]==N
和neighbors[3*i+1]==N
。
答案 0 :(得分:1)
您正在使用的数据结构是Graph。但Graph是一个更通用的概念,其中一个节点可以有任意数量的邻居。
因为你的问题比较严格,所以说每个节点最多有3个邻居。 我在评论中建议的解决方案是可以用于所有图表的一般解决方案,并且也适用于您的情况。
声明图表:
vector<vector<int> > graph (N);
如果a
到b
有边缘,请执行以下操作:
graph[a].push_back (b);
检索节点a
的邻居:
for (int i=0;i<graph[a].size();i++)
// Do whatever you want with the neighbour. The variable graph[a][i] holds the neighbour number
现在解决你最多3个邻居的问题。 根据我的最佳解决方案是:
struct node
{
int data; // Some data related to the node. This is optional.
int neigh_1;
int neigh_2;
int neigh_3;
}
将图形作为节点数组:
node[N] graph;
这也需要 3 * N 内存。但这是你所做的更好的方法。让我解释一下:
当你说给我节点x
的邻居时:
您的方法将访问内存位置 x,3 * x,3 * x + 4,3 * x + 8 。
我的方法将访问内存位置 x,x + 4,x + 8,x + 16
等等!当我们只想要它的邻居时,为什么我们访问x
?这是一个有效的问题,但如果您需要在节点处理某些值或将某些信息存储在节点本地,那么我们必须访问x
。
注意:我建议的方法不会比你的方法更差。但对于一般情况来说肯定会表现得更好。
为什么我的方法更好?
我的方法会导致较小的cache misses,因为我的空间locality of reference更好。
如果您不关心缓存的工作,简单来说,我的方法将访问彼此更接近的位置,因此很有可能已经在更快的内存缓存中将导致更快的访问。
也有人可能会争辩说我们应该只在需要时为邻居声明内存。基本上vector
解决方案就是这样做的。但是在这种情况下它不会表现良好,因为即使声明指针也需要8个字节。但是使用该空间,您可以存储2个整数的信息,即有关2个邻居的信息。
因此动态分配内存不会节省任何空间,因为最大邻居为3。
答案 1 :(得分:1)
您可以简单地定义一个包含节点值和邻居索引的结构,如
#include <vector>
#include <iostream>
struct vertex{
int data;
std::vector<int> neighbours;
};
下面给出了为每个节点添加2个邻居的示例程序。每个节点都有一个索引平方值。
int main(){
vertex v[5];
for (int i=0;i<5;i++){
v[i].data = i*i;
}
for (int i=0;i<5;i++){
v[i].neighbours.push_back((i+1) % 5);
v[i].neighbours.push_back((i+2) % 5);
}
for (int i=0;i<5;i++){
std::cout << "vector " << i << " has value " << v[i].data << std::endl;
for (int j=0;j<v[i].neighbours.size();j++){
int nodeNum = v[i].neighbours[j];
std::cout << "vector " << i << " has neighbours " << v[i].neighbours[j] << " with data " << v[nodeNum].data << std::endl;
}
std::cout << std::endl ;
}
return 0;
}
这将输出以下
vector 0 has value 0
vector 0 has neighbours 1 with data 1
vector 0 has neighbours 2 with data 4
vector 1 has value 1
vector 1 has neighbours 2 with data 4
vector 1 has neighbours 3 with data 9
vector 2 has value 4
vector 2 has neighbours 3 with data 9
vector 2 has neighbours 4 with data 16
vector 3 has value 9
vector 3 has neighbours 4 with data 16
vector 3 has neighbours 0 with data 0
vector 4 has value 16
vector 4 has neighbours 0 with data 0
vector 4 has neighbours 1 with data 1
因为我们已经为邻居使用了vector。我们可以为节点分配任意数量的邻居。这是一般情况。并且也适用于您的要求。希望这有帮助