在我们的一个应用程序的核心,我们必须合并键值列表。因为这个合并函数一直被调用,所以它必须尽可能快。交换记忆以获得额外的速度是可以接受的。
我们的应用程序是用Delphi编写的,所以我将引用一些特定于Delphi的例程,但我认为这个问题可能与用于解决它的语言无关。
'Key1=Value1'#13#10'Key2=Value2'#10'Key3=Value3'#13#10#10'Key4=Value4'
。请注意,键和值之间用'='分隔,键值对可以由字符#13
和#10
的任意组合分隔。 #13#10
分隔。我的解决方案的核心是一个字典,它将键(字符串)映射到指向的指针以及包含该值的内存块的长度。此地图按键排序。它可以在使用前重置,并在合并例程的多个调用之间共享,因此我们节省了映射及其条目的内存分配和释放。 对每个输入键值列表执行以下操作:
#13
和#10
个字符,以转到下一个键的开头。填充地图后,通过迭代地图,连接键,键值分隔符,基于给定位置和长度的值的副本以及每个条目的“\ r \ n”来构建输出字符串。不要忘记最后的空终止符。
我尝试过以下操作,使用QueryPerformanceCounter Windows API函数测量性能。
您能想到哪些其他优化甚至是完全不同的算法?
答案 0 :(得分:1)
据我所知,你的解决方案很好,很难改进。
我要做的唯一建议是对字典使用散列而不是键和二进制搜索的排序列表。假设其性能合理,您可以使用Delphi的TDictionary<TKey,TValue>
。对于TKey
,您将使用实现地图的自定义记录(位置和长度)。同样适用于TValue
。您必须实现自己的比较器,这可以很容易地完成,而不会产生堆分配。
说完所有这些之后,你是否100%确定堆分配与你认为它们对于这个应用程序一样邪恶?您应该尝试使用TDictionary<string,string>
进行简单的实现并对应用进行概要分析,以证明它在字典代码中花费了大量时间。这种方法的另一个好处是,如果确实堆分配是一个问题,您可以使用基于string
的版本作为参考实现进行测试。您的指针偏移+基于长度的版本肯定是一个错误工厂。
答案 1 :(得分:0)
句子“这个地图按键排序”和短语“保持地图排序”和东西重新指针和长度使得听起来像是在每次插入数组后对指针数组进行排序。如果是这样,您可能会发现Timsort的运行速度比Quicksort快。
维护平衡搜索树可能是更好的方法。 AA tree很容易编码,其性能类似于红黑树,即 O(ln n)插入,查找和删除。如果您确实在每次插入后对数组进行排序,则使用搜索树会将插入时间从O(n ln n)减少到O(ln n)。
要按顺序读出密钥,请使用在最坏情况下运行时间为O(n ln n)的in-order traversal。
已更新:已按顺序更正预订