c++ - 简单无向图的表示
问题描述
我需要你的专业知识:
我即将在 C++ 中实现一个图形类并考虑正确的表示。这些图简单且无向。顶点的数量现在最多可达 1000 个,但将来可能会更高。边数高达 200k 甚至更高。每个顶点都有一个颜色(int)和一个id(int)。边传输的信息不比连接到顶点的信息多。
我存储图表,只需要访问 x 和 y 是否连接 - 这是我经常需要的。初始化后,我永远不会删除或添加新的顶点或边(N = 顶点数,M = 从一开始就给出的边数)!
我已经可以使用的一种表示形式:
一个邻接列表展开成一个长长的列表。除了这个表示之外,还有一个数组,其中包含每个顶点的起始索引。存储 O(2M) 并检查 x 和 y 之间的边缘是否平均为 O(n/m)
我想到的一个表示:
这个想法是,而不是将邻接列表展开到一个数组中,而是使用邻接矩阵来完成。那么存储 O(N^2)?是的,但我想在一个字节之外的一位中存储一个边。(实际上是对称的 2 位)示例:假设 N=8,然后创建一个长度为 8(64 位)的向量<uint8_t>。在 0 上初始化每个条目。如果顶点 3 和顶点 5 之间有一条边,则将 pow(2,5) 添加到属于顶点 3 的向量的条目并对称。因此,当 3 和 5 之间有一条边时,在顶点 5 的位置处的顶点 3 的条目中有一个 1。将我的图插入这个数据结构后,我认为应该能够在恒定时间内访问邻域二元运算:3 和 5 是否相连?是,如果 v[3] ^ pow(2,5) == 0。当顶点数多于 8 时,
您如何看待第二种解决方案 - 它是否可能已经知道并正在使用?考虑 O(1) 的访问我错了吗?没有真正的性能改进是否需要付出很多努力?
将两种表示加载到一个大列表中的原因是由于有人告诉我缓存改进。
我很高兴收到关于这个想法的一些反馈。我可能会走得很远 - 在这种情况下请善待:D
解决方案
具有 200,000 条边的 1000x1000 矩阵将非常稀疏。由于图是无向的,矩阵中的边将被写入两次:
VerticeA -> VerticeB and VerticeB -> VerticeA
您最终将填满矩阵的 40%,其余的将是空的。
边缘
The best approach I can think of here is to use a 2D vector of booleans:
std::vector<std::vector<bool>> matrix(1000, std::vector<bool>(1000, false));
The lookup will take O(1) time and std::vector<bool>
saves space by using a single bit for each boolean value. You will end up using 1Mbit or ~128kB (125 kB) of memory.
The storage is not necessarily an array of bool values, but the library implementation may optimize storage so that each value is stored in a single bit.
This will allow you to check for an edge like this:
if( matrix[3][5] )
{
// vertice 3 and 5 are connected
}
else
{
// vertice 3 and 5 are not connected
}
Vertices
If the id values of the vertices form a continuous range of ints (e.g. 0,1,2,3,...,999) then you could store the color information in a std::vector<int>
which has O(1) access time:
std::vector<int> colors(1000);
This would use up memory equal to:
1000 * sizeof(int) = 4000 B ~ 4 kB (3.9 kB)
On the other hand, if the id values don't form a continuous range of ints it might be a better idea to use a std::unordered_map<int, int>
which will on average give you O(1) lookup time.
std::unordered_map<int, int> map;
So e.g. to store and look up the color of vertice 4:
map[4] = 5; // assign color 5 to vertice 4
std::cout << map[4]; // prints 5
The amount of memory used by std::unordered_map<int, int>
will be:
1000 * 2 * sizeof(int) = 8000 B ~ 8 kB (7.81 kB)
All together, for edges:
Type | Memory | Access time |
---|---|---|
std::vector<std::vector<bool>> |
125 kB | O(1) |
and for vertices:
Type | Memory | Access time |
---|---|---|
std::vector<int> |
3.9 kB | O(1) |
std::unordered_map<int, int> |
7.8 kB | O(1) on avg. |
推荐阅读
- apache-spark - PySpark - 如何根据列中的两个值从数据框中过滤出连续的行块
- azure - ApplicationInsights 持续导出
- flutter - Navigator.pushNamed 更改路由到另一个屏幕后颤振构建旧屏幕?
- c++ - 在基类中使用派生类的赋值运算符
- html - 如何在鼠标移出时从右侧动画下划线宽度?
- reactjs - useGesture 和 useSpring 键盘支持?
- mysql - 如何在 Docker Compose 中初始化 MySql 数据库
- grafana - 如何在 grafana 中进行生产构建?
- networking - 允许 VM 连接到 Internet 的防火墙规则
- mysql - 对两个字段的数据进行排序