【发布时间】:2011-05-05 14:41:09
【问题描述】:
我需要一个以Ruby 语言实现的数据结构来容纳大量不同的网址(例如10**10 片段),所以性能是我关心的问题。
我正在使用Array 并保持其元素有序,因此我可以执行binary search 来查找是否已经存在或者快速插入网址的位置。
我是这样写的:
class UrlStore
def initialize(*args)
@urls = []
args.each { |e| add(e) unless e.class != String }
end
def add(url)
p = find(url)
@urls.insert(p, url) unless p.class == String
end
def find(url)
l, m, h = 0, 0, @urls.size - 1
while l <= h do
m = l + (h - l) / 2
b = url <=> @urls[m]
if b == 0
return m.to_s
elsif b == 1
l = m + 1
else
h = m - 1
end
end
return l
end
end
find 方法如果找到,将返回 url 在托管数组中的位置,但以String 形式返回,以便与找到的插入位置进行区分;否则,返回一个整数(Fixnum),告诉 url 应该去哪里以保持数组有序。
但请注意,我使用Array#insert 在指定位置添加元素。我的直觉告诉我,这种方法会将插入点后的所有元素向后移动一步,这可能会导致严重的性能下降。 Array 模块不在标准库中,它是 Ruby 的固有数据类型,所以我不知道我是否正确。
可能是用于托管此类任务的数据结构太天真了。 所以任何人都可以分享一个很棒的。
【问题讨论】:
-
假设每个 URL 平均有 40 个字节。对于 1e10 URL,存储信息需要超过 370 GB 的内存。显然您没有用于此的 RAM,因此显然您需要一个数据库。
-
无论如何,二分搜索不是要走的路。如果可以的话,你会使用哈希查找(参见 Set 解决方案)
-
数组非常适合队列和堆栈,您可以在其中按顺序添加和删除元素,但是当您必须搜索大型数组时它们真的会崩溃。当您随机访问一个元素或需要检查它的存在时,哈希值会好得多。当您突破内存限制时,您需要考虑将查找和存储卸载到数据库。至少一个键/值存储,或类似 SQLite 的东西会有所帮助。我更喜欢 Postgres 或 MySQL,因为它们非常聪明,并且随着应用需求的增长提供了许多有用的功能。
标签: ruby performance data-structures