存储顶点的所有邻居,快速找到顶点的邻居

时间:2016-10-07 02:26:55

标签: c++ algorithm vector

假设我有从N0标记的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

我对我的方法感到不舒服的事情:

  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)

  2. 如果我想查找N的邻居,每次我需要测试vertex[i]neighbors[3*i]==Nneighbors[3*i+1]==N

2 个答案:

答案 0 :(得分:1)

您正在使用的数据结构是Graph。但Graph是一个更通用的概念,其中一个节点可以有任意数量的邻居。

因为你的问题比较严格,所以说每个节点最多有3个邻居。 我在评论中建议的解决方案是可以用于所有图表的一般解决方案,并且也适用于您的情况。

声明图表:

vector<vector<int> > graph (N);

如果ab有边缘,请执行以下操作:

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。我们可以为节点分配任意数量的邻居。这是一般情况。并且也适用于您的要求。希望这有帮助