Ruby on rails “散列”;有“U键”;Ruby中的复杂性

Ruby on rails “散列”;有“U键”;Ruby中的复杂性,ruby-on-rails,ruby,algorithm,hash,time-complexity,Ruby On Rails,Ruby,Algorithm,Hash,Time Complexity,我有一个hashvars={“a”=>“Name”,“b”=>“Address”,“c”=>“Phone”}。我想检查这一行的性能: vars.has_key(:b)? 是O(1)还是O(散列大小)?方法的预期复杂性是恒定的 简单基准: require 'benchmark' iterations = 10_000 small = 10 big = 1_000_000 small_hash = {} big_hash = {} (1..small).each

我有一个hash
vars={“a”=>“Name”,“b”=>“Address”,“c”=>“Phone”}
。我想检查这一行的性能:

vars.has_key(:b)?

是O(1)还是O(散列大小)?

方法的预期复杂性是恒定的

简单基准:

require 'benchmark'

iterations = 10_000
small      = 10
big        = 1_000_000

small_hash = {}
big_hash   = {}

(1..small).each do |i|
  small_hash[i] = i
end

(1..big).each do |i|
  big_hash[i] = i
end

Benchmark.bmbm do |bm|
  bm.report('Small Hash') do
    iterations.times { small_hash.has_key?(1) }
  end

  bm.report('Big Hash') do
    iterations.times { big_hash.has_key?(1) }
  end
end
运行测试:

$ ruby has_key_test.rb 
                 user     system      total        real
Small Hash   0.000000   0.000000   0.000000 (  0.001167)
Big Hash     0.000000   0.000000   0.000000 (  0.001171)

是的,我认为我们可以考虑成本常数O(1)(至少不检查内部MRI实现)。


具有1个条目或100万个条目的哈希之间的差异是。。。最小值。

源代码的
键为()

st_lookup
包含以下片段():


tbl->entries\u packed=size散列是直接访问,不像堆栈(数组),需要遍历每个元素,直到找到所需的元素。因此,
has_key
不应该依赖于散列的大小(有待确认,但我非常确定)来执行良好的基准测试,您需要对调用的方法执行多个迭代。事实上,我建议您至少进行10^5次迭代以获得一个好的近似值。@IvayloStrandjev是的,您是对的,这只是一个快速的近似值。我将使用
Benchmark.bmbm
和更多迭代来更新它。@markets-那么
有什么价值呢?
?我尝试将
has\u key?(1)
修改为
has\u value?(大-1)
,然后大哈希将花费(大/小)x时间。所以我认为
的时间复杂度是O(n),如果键不是符号而是字符串呢?我的键不是符号而是整数。只需将
o[x]=:a
替换为
o[x.to_s]=:a
并将
h.has_key?(t)
替换为
h.has_key?(t.to_)
并执行代码…@忘记你为什么不使用数组?你会省下很多额外的线路…@IvayloStrandjev我能做到。。。我只用了2分钟就完成了这个基准测试,并进行了大量的复制粘贴。读者如何评估您的断言的有效性?如果你不是Matz(或其他几个人中的一个),你需要提供一份推荐信或证明。
def fake_h(n)
  n.times.inject({}){|o,x| o[x] = :a; o}
end

n = 1000000;
h1 = fake_h(1);
h10 = fake_h(10);
h100 = fake_h(100);
h1000 = fake_h(1000);
h10000 = fake_h(10000);
h100000 = fake_h(100000);
h1000000 = fake_h(1000000);

Benchmark.bm do |x| 
  x.report { n.times{|t| h1.has_key?(t) } }
  x.report { n.times{|t| h10.has_key?(t) } }
  x.report { n.times{|t| h100.has_key?(t) } }
  x.report { n.times{|t| h1000.has_key?(t) } }
  x.report { n.times{|t| h10000.has_key?(t) } }
  x.report { n.times{|t| h100000.has_key?(t) } }
  x.report { n.times{|t| h1000000.has_key?(t) } }
end

# Result :
    user     system      total         real
0.200000   0.000000   0.200000 (  0.204647)
0.210000   0.000000   0.210000 (  0.205677)
0.210000   0.000000   0.210000 (  0.214393)
0.210000   0.000000   0.210000 (  0.206382)
0.210000   0.000000   0.210000 (  0.208998)
0.200000   0.000000   0.200000 (  0.206821)
0.220000   0.000000   0.220000 (  0.213316)
rb_hash_has_key(VALUE hash, VALUE key)
{
    if (!RHASH(hash)->ntbl)
        return Qfalse;
    if (st_lookup(RHASH(hash)->ntbl, key, 0)) {
        return Qtrue;
    }
    return Qfalse;
}
if (table->entries_packed) {
    st_index_t i = find_packed_index(table, hash_val, key);
    if (i < table->real_entries) {
        if (value != 0) *value = PVAL(table, i);
        return 1;
    }
        return 0;
    }
#define MAX_PACKED_HASH (int)(ST_DEFAULT_PACKED_TABLE_SIZE * sizeof(st_table_entry*) / sizeof(st_packed_entry))
tbl->entries_packed = size <= MAX_PACKED_HASH;