【发布时间】:2014-10-02 13:45:21
【问题描述】:
我可能只是想在这里做一些疯狂的事情,所以让我先解释一下我的用例:
我在 Ruby 中有一个对象图,它只包含基本的 JSON 类型(字符串、数字、数组、哈希、真、假、空值)。我希望最终将此图序列化为 JSON。
问题是我无法控制图中所有对象的来源。这意味着对象图中包含的某些字符串可能被标记为错误的编码(例如,实际上只是一堆随机垃圾字节的字符串最终被标记为 UTF-8 编码)。这会导致 JSON 序列化失败(因为 JSON 只支持 UTF-8 编码的字符串)。
我有一个处理这些有问题的字符串的策略,基本上包括用每个字符串的转换版本替换它们(确切的转换并不真正相关)。
为了将这种转换应用于字符串,我需要遍历整个对象图并找到所有这些对象。这对于使用标准深度优先搜索递归实现是微不足道的。一个问题是我想避免改变原始对象图或其中的任何字符串,所以我基本上是在遍历它时构建对象图的副本(只有无问题的叶节点直接从新图,以及所有其他被欺骗的节点)。
这一切都有效,并且相当有效,在转换后的对象图中保存了非叶节点的重复。问题是它有时会得到非常深嵌套的对象图,因此递归有时会产生SystemStackError。
我已经使用带有Enumerator 对象堆栈的 DFS 实现了一个非递归解决方案,但它似乎比递归解决方案慢得多(可能是因为 Enumerators 和在每个 Enumerator 末尾引发的愚蠢的 StopIteration 异常。
广度优先搜索似乎不合适,因为我认为在访问给定节点时没有办法确定返回到根的路径,我认为我需要它来构建树的副本。
我对 BFS 的看法有误吗?是否有其他技术可以用来在不递归的情况下完成这种遍历?这都是疯子吗?
【问题讨论】:
-
为什么需要遍历栈进行拷贝?要复制图,请保留将原始节点映射到复制节点的哈希。搜索原文。检查每条边的目的地,看看它是否在散列中。如果不是,则复制目标,将 original->copy 对放入哈希中,然后将新副本添加到搜索队列/堆栈中。如果它已经在散列中,只需将目标指针设置为副本。使用此算法,您使用的搜索无关紧要。一堆枚举器很疯狂。保留一堆完全未探索的孩子,而不是部分探索的父母!
-
JSON 对象需要嵌套多深才能为您提供
SystemStackError?我印象深刻。
标签: ruby json algorithm recursion