【问题标题】:Hash tables with long (100+ character) key names具有长(100 多个字符)键名的哈希表
【发布时间】:2019-02-23 15:28:16
【问题描述】:

我正在为我的一个实用程序开发一个数据结构,我很想制作一个哈希表,其中的键是一个很长的字符串,特别是一个文件路径。从数据的角度来看,这有很多原因,主要是保证路径是唯一的这一事实。也就是说,我看到的每个哈希表示例都有非常短的键和可能很长的值。所以,我想知道这是否只是简单示例的功能?或者是否有不使用长键的性能或技术原因? 我将使用$variable = New-Object Collections.Specialized.OrderedDictionary 进行与版本无关的排序,如果这有什么不同的话。

【问题讨论】:

  • 长键会更慢,是的(因为计算更长字符串的哈希码需要更长的时间)。这会成为您的上下文的问题吗?可能不会 - 但您需要进行概要分析才能 100% 确定。
  • 值得注意的是sorted dictionary will use more memory than a sorted list,插入和检索时间几乎相同。您可能希望将此因素纳入您的决定。

标签: c# powershell ordereddictionary


【解决方案1】:

我认为你可以拥有长字符串的键。

在底层,OrderedDictionary 中的键查找是在

中进行的
if (objectsTable.Contains(key)) {

objectsTable 是 Hashtable 类型

如果你遵循在 Hashtable 类中获取哈希的链,你会得到这个: https://referencesource.microsoft.com/#mscorlib/system/collections/hashtable.cs,4f6addb8551463cf

    // Internal method to get the hash code for an Object.  This will call
    // GetHashCode() on each object if you haven't provided an IHashCodeProvider
    // instance.  Otherwise, it calls hcp.GetHashCode(obj).
    protected virtual int GetHash(Object key)
    {
        if (_keycomparer != null)
            return _keycomparer.GetHashCode(key);
        return key.GetHashCode();
    }

那么,问题就变成了,在字符串上获取 HashCode 的成本是多少? https://referencesource.microsoft.com/#mscorlib/system/string.cs

GetHashCode 函数是一个循环,但它只是一个 O(n) 函数,因为它只根据字符串长度增长。您会注意到哈希的计算在 32 位机器上与其他机器上有些不同,但 O(n) 是算法扩展的更糟糕的情况。

函数还有其他部分,但我认为这是关键部分,因为它是可以增长的部分(src 是 char*,表示指向字符串中的字符)。

#if WIN32
                    // 32 bit machines.
                    int* pint = (int *)src;
                    int len = this.Length;
                    while (len > 2)
                    {
                        hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
                        hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
                        pint += 2;
                        len  -= 4;
                    }

                    if (len > 0)
                    {
                        hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
                    }
#else
                    int     c;
                    char *s = src;
                    while ((c = s[0]) != 0) {
                        hash1 = ((hash1 << 5) + hash1) ^ c;
                        c = s[1];
                        if (c == 0)
                            break;
                        hash2 = ((hash2 << 5) + hash2) ^ c;
                        s += 2;
                    }
#endif

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-01
    • 2015-07-26
    • 1970-01-01
    • 2011-06-09
    • 2010-10-15
    • 1970-01-01
    • 2013-05-04
    • 2017-03-31
    相关资源
    最近更新 更多