在哈希冲突中,CPython如何知道在索引HASHVALUE中存储哪个值以及哪个值存储在RESOLUTIONINDEX

时间:2015-10-04 22:27:49

标签: python dictionary hash collision

如果我有一个dict,例如{ key1 : value1, key2 : value2,..., key17:value17 },并且2个键给出相同的散列,那么key13和key5在散列时都给出12,因为据我所知它python实现了一个冲突解决方法(开放寻址)如果我没有弄错的话)来解决这个问题。 所以,比较value5将存储在索引12处,而value13将存储在由碰撞解决方法确定的另一个开放索引中。

这是我感到迷惑的棘手部分:为了检索值(例如来自key5),CPython解释器是否散列密钥并从索引HASHVALUE中检索值? 那可能不对,因为那么解释器如何知道value13是否属于key5,还是因为碰撞而位于不同的索引中?

我尝试查看https://github.com/python/cpython/blob/master/Objects/dictobject.c#L1041

中的C代码

,功能似乎是

PyObject *
PyDict_GetItem(PyObject *op, PyObject *key)
{
    Py_hash_t hash;
    PyDictObject *mp = (PyDictObject *)op;
    PyDictKeyEntry *ep;
    PyThreadState *tstate;
    PyObject **value_addr;

    if (!PyDict_Check(op))
        return NULL;
    if (!PyUnicode_CheckExact(key) ||
        (hash = ((PyASCIIObject *) key)->hash) == -1)
    {
        hash = PyObject_Hash(key);
        if (hash == -1) {
            PyErr_Clear();
            return NULL;
        }
    }

    #/* We can arrive here with a NULL tstate during initialization: try
       #running "python -Wi" for an example related to string interning.
       #Let's just hope that no exception occurs then...  This must be
       #_PyThreadState_Current and not PyThreadState_GET() because in debug
       #mode, the latter complains if tstate is NULL. */
    tstate = (PyThreadState*)_Py_atomic_load_relaxed(
        &_PyThreadState_Current);
    if (tstate != NULL && tstate->curexc_type != NULL) {
       # /* preserve the existing exception */
        PyObject *err_type, *err_value, *err_tb;
        PyErr_Fetch(&err_type, &err_value, &err_tb);
        ep = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr);
       # /* ignore errors */
        PyErr_Restore(err_type, err_value, err_tb);
        if (ep == NULL)
            return NULL;
    }
    else {
        ep = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr);
        if (ep == NULL) {
            PyErr_Clear();
            return NULL;
        }
    }
    return *value_addr;
}

但我的C知识非常缺乏,我坦率地不明白这一半的含义。

1 个答案:

答案 0 :(得分:0)

密钥与其关联值

一起存储

CPython哈希表中的每个索引都与包含三个字段的结构相关联:哈希值,键指针和值指针:

typedef struct {
    Py_ssize_t me_hash;
    PyObject *me_key;
    PyObject *me_value;
} PyDictEntry;

如何处理哈希冲突

在您的方案中,{hash5, key5, value5}存储在索引12{hash13, key13, value13}存储在由开放寻址冲突解决方案选择的备用索引中。

在索引key5查找12时,Python会验证密钥是否匹配,然后返回关联的value5

相反,当首次在索引key13查找12时,Python会注意到key13 != key5并且不会返回value5。相反,它会跳转到key13匹配的备用索引,然后返回关联的value13

结论

您询问" CPython如何知道哪个值存储在索引HASHVALUE以及哪个值存储在RESOLUTIONINDEX"。答案是值与关联键一起存储,从而可以知道哪个值与哪个键相关联。