我可以向你保证,这个功能strcmp
绝对不是瓶颈。通常,strcmp 进行了很好的优化,可以根据架构对超过 4/8 字节的字符串进行 32 位或 64 位比较。newlib 和 GNU libc 都这样做。但是,即使您要查看两个字符串中的每个字节 20 次,也没有这里选择的算法和数据结构那么重要。
真正的瓶颈是 O(N) 搜索算法。文件中的单个 O(N log N) 传递可用于在适当的数据结构(无论是普通的 BST、trie 还是简单的排序数组)上进行 O(log N) 查找。
忍受我在这里 - 很多数学如下。但我认为这是一个很好的机会来说明为什么算法和数据结构的选择有时比字符串比较的方法更重要。史蒂夫谈到了这一点,但我想更深入地解释一下。
在 N=1e6 时,log(1e6, 2) = 19.9,因此对理想数据结构进行最多 20 次比较。
目前,您正在对 O(N) 或 1e6 操作进行最坏情况搜索。
所以假设你只是用 O(log N) 插入时间构建一个红黑树,然后你插入 N 个项目,构建树的时间是 O(N log N)。所以这是构建树所需的 1e6 x 20 或 20e6 操作。
在您当前的方法中,构建数据结构是 O(N) 或 1e6 次操作,但最坏情况下的搜索时间也是 O(N)。因此,当您读取文件并仅执行 20 次搜索操作时,理论上最坏的情况是 21,000,000 次操作。相比之下,红黑树和 20 次搜索的最坏情况是 20,000,400 次操作,或 999,600 次操作比在未排序数组上的 O(N) 搜索要好。因此,在 20 次搜索时,您就处于更复杂的数据结构真正获得回报的第一个点。但看看 1000 次搜索会发生什么:
未排序数组 = 初始化 + 1000 x 搜索时间 = O(N) + 1000 * O(N) = 1,000,000 + 2,000,000,000 = 2,001,000,000 次操作。
红黑 = 初始化 + 1000 x 搜索时间 = O(N log N) + 1000 * O(log N) = 20,000,000 + 20,000 = 20,020,000 次操作。
2,001,000,000 / 20,020,000 ~= 100 倍于 O(N) 搜索的操作。
在 1e6 次搜索中,即 (1e6 + 1e6 * 1e6) / (20e6 + 1e6 * 20 ) = 25,000 倍的操作。
假设您的计算机可以在 1 分钟内处理进行 log N 搜索所需的 40e6 次“操作”。使用您当前的算法完成相同的工作需要 25,000 分钟或 17 天。或者另一种看待方式是,O(N) 搜索算法只能处理 39 次搜索,而 O(log N) 算法可以执行 1,000,000 次。你做的搜索越多,它就越难看。
有关数据结构和算法的几种更好选择,请参阅 Steve 和 dirkgently 的回复。我唯一需要注意的是,qsort()
史蒂夫建议的最坏情况复杂度可能为 O(N*N),这比使用堆排序或各种树状结构得到的 O(N log N) 还要糟糕得多结构。