【问题标题】:How to implement a static graph in C如何在 C 中实现静态图
【发布时间】:2010-07-06 12:15:36
【问题描述】:

我需要在用 C 语言编写的游戏服务器中存储游戏地图的图表。

该图有大约 200 个节点和 3 种可以连接两个节点的边(这三种也可以重叠:例如,一个节点可以由两种不同类型的 2 条边连接)。一个节点的最大度数大概是5-6个节点。

我想要的是让这个静态结构以一种有效的方式实现,让我可以做一些简单的操作,比如

  • n1 是否连接到 n2? (在肯定响应的情况下具有各种边缘)
  • n1 连接到什么? (具有各种边缘或特定边缘)

但在多线程环境中,因为会有很多游戏实例依赖于同一个静态图。

由于图表无法修改且结构众所周知,我确信有一些技巧可以以一种很酷的方式实现它,以尽可能使用最少的资源。

我现在想避免使用 STL 或 Boost.. 你有任何关于适合的数据结构的线索吗?

(这不是一个过早的优化,事实是它会在 vps 上运行,而且我没有很多内存和 cpu 能力,所以我需要保持紧张)

编辑:只是因为我忘记了(感谢让我意识到)图是无向所以每条边都是对称的..

提前致谢

【问题讨论】:

    标签: c data-structures graph


    【解决方案1】:

    许多答案都是可能的。这取决于您拥有相对较少的节点这一事实。这种方法的优势可能是无与伦比的性能。

    这个想法是将您的图表表示为一个 200x200 的字节矩阵,每个条目代表一条边。该字节为您提供 256 个不同的可能值,其中 0 显然表示“无连接”,任何非零位组合最多可以表示 8 种不同的边缘类型。

    让这个矩阵的“行”为起始节点,“列”为目的地。初始化结构,使得对于连接一个节点与另一个节点的每条边,在开始/结束的交点处都有一个值。该值可以是表示边缘类型的位的组合。

    要判断一个节点是否连接到另一个节点,只需查询一个节点与另一个节点相交处的字节:如果那里有一个非零值,那么就有一个连接,该值会告诉你是什么类型。

    对于 200 个节点,此数据结构将占用 40 KB,这相当适中。一旦超过 1000 个节点,它就不会很好地扩展。

    只要没有东西(除了一次性初始化)写入这个结构,它自然是线程安全的,因为它的状态永远不会改变。

    【讨论】:

    • 啊,打败我了。只是想补充一点,如果图形是无向的,您只需要存储一半的数组。 (20KB)
    • 如果我正在实施,我会懒得花很多心思来节省一半所需的内存。此外,该问题暗示 OP 还将寻找反向连接。我在这里的方法是“留给读者的改进”:)
    • 就此而言,如果有三个可能的连接,您应该只需要每对 3 位或 14925 个字节。 (如果它是三个 200*199 位 = 25 * 199 字节的数组,而不是每对使用 3 个连续位,查找会更容易)
    • @Pete:好主意!看看 OP 的(更新的)问题,似乎内存确实很宝贵,所以节省下来可能是值得的。如果图表确实是无向的,则可以合并@wds 的建议以再节省 50%。所以我们会减少到 7500 字节?开始看起来不错。而且仍然非常快。
    • 是的,如果你把它切成两半,标准做法就是找到一个从 (a,b) 坐标到线性地址空间的良好映射函数,然后在你寻址一个元素时设置宏。 (如果 a a+b-1)。皮特的建议需要更多技巧。使用字节的好处是它很容易使用,您可以进行一些测试(是否有链接)而无需使用掩码。我认为这是内存/cpu 的权衡。
    【解决方案2】:

    由于度数是有限的,您可以通过一个结构体来表示一个节点,该结构体具有指向其他节点的指针数组(每个边缘类型一个数组),从而获得非常好的性能。

    无论您选择哪种数据结构,如果您的图形是只读的,您就可以避免担心多线程(允许多线程访问它而无需同步)。

    【讨论】:

    • 大多数情况下要避免 - 您仍然需要在图表中设置数据和将指向数据的指针提供给线程之间设置围栏,因此您需要在启动时将数据传递给线程,或者添加自己围起来。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    • 2021-09-06
    • 2010-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多