存储顶点的所有邻居,快速找到顶点的邻居
Store the all the neighbors of the vertexes, find a vertex's neighbors quickly
假设我有从0
到N-1
标记的N
顶点。每个顶点具有最多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
到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
和neighbors[3*i+2]==N
。
您正在使用的数据结构是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
。
注意:我建议的方法不会比你的方法表现得更差。但在一般情况下,它肯定会表现得更好
为什么我的方法更好
我的方法将导致较少的缓存未命中,因为我具有更好的引用空间局部性。
如果你不关心缓存的工作,简单地说,我的方法将是访问彼此更近的位置,因此很有可能已经在更快的内存缓存中,这将导致更快的访问。
还有人可能会争辩说,只有在需要的时候,我们才应该为邻居声明内存。本质上,vector
解决方案就是这样做的。但在这种情况下,它不会很好地执行,因为即使声明一个指针也需要8个字节。但有了这个空间,你可以存储2个整数的信息,即关于2个邻居的信息。
因此,动态分配内存不会节省任何空间,因为最大邻居为3。
您可以简单地定义一个结构,该结构包含节点值和邻居的索引,如
#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
因为我们用矢量表示邻居。我们可以为我们的节点分配任意数量的邻居。这是一般情况。也适用于您的要求。希望这能帮助
- 如何循环打印顶点结构
- D3D11-将混合权重和索引传递到顶点着色器
- 从返回的顶点缓冲区查询顶点结构
- Vulkan 中的动态顶点缓冲区格式设置
- 在顶点着色器中使用 OpenGl 的未声明标识符,我在顶点着色器中绘制三角形时遇到问题
- 如何将一半传递给顶点着色器?
- 在 DirectX 11 中从 GPU 读回顶点缓冲区(并获取顶点)
- QT QOpenGLWidget:如何在不使用数据块复制的情况下修改VBO中的单个顶点值?
- 使用 OpenGL 4.5 更改所选顶点的颜色
- Direct3D 11 - HLSL - 获取顶点索引 ID
- 创建异构顶点数据数组的可移植方法
- 使用 glvertex4i 传递网格面索引时的顶点着色器错误
- 优化在 Z^3 中查找邻居
- 无法从 cso 文件创建顶点着色器(从 fx 文件创建)
- 将消息从节点发送到其邻居
- OpenGL 相机移动程序顶点着色器问题
- 如何在任意网格上找到顶点的邻居
- 在Boost Graph库中选择给定顶点的随机进出邻居的有效方法
- 如何避免在BFS中进一步搜索顶点的邻居?我正在使用提升图形库
- 存储顶点的所有邻居,快速找到顶点的邻居