• Python中Dict的查找


    Dict的类型的查找使用的是lookdict函数

    static PyDictKeyEntry *
    lookdict(PyDictObject *mp, PyObject *key,
             Py_hash_t hash, PyObject ***value_addr)

    函数的参数中,*value_addr是指向匹配slot中值的指针。 这个函数在正确的情况下一定会返回一个指向slot的指针,出错则会返回NULL。 如果成功找到了匹配的slot,则返回对应的slot; 如果没有匹配的slot,则返回查找链上第一个未被使用的slot。 该slot可以是unused状态,也可以是dummy状态。

        mask = DK_MASK(mp->ma_keys);
        ep0 = &mp->ma_keys->dk_entries[0];
        i = (size_t)hash & mask;

    计算了slot的初始位置,把hash值映射到slot table的下标范围内。 初始位置=hash&mask,mask=dk_size-1

        if (ep->me_key == NULL || ep->me_key == key) {
            *value_addr = &ep->me_value;
            return ep;
        }

    如果找到了匹配的key或unused slot,返回该结果即可。

        if (ep->me_key == dummy)
            freeslot = ep;
        else {
            if (ep->me_hash == hash) {
                startkey = ep->me_key;
                Py_INCREF(startkey);
                cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
                Py_DECREF(startkey);
                if (cmp < 0)
                    return NULL;
                if (ep0 == mp->ma_keys->dk_entries && ep->me_key == startkey) {
                    if (cmp > 0) {
                        *value_addr = &ep->me_value;
                        return ep;
                    }
                }
                else {
                    /* The dict was mutated, restart */
                    goto top;
                }
            }
            freeslot = NULL;
        }

    进一步的比较。 若该slot状态为dummy,则用freeslot记录该slot并继续搜索; 如果该slot的hash值与待搜索key的hash相同,那么对两个key进行比较。 这里的PyObject_RichCompareBool是一个比较函数,其第三个参数为比较的操作。 如果操作结果为true,返回1;为false,返回0;比较出错,返回-1。 比较出错的情况下会返回NULL,比较成功(在这里为相等)返回该slot,比较不成功则继续进行搜索。 这一部分进行了第一次的搜索;在dict容量不太满时,一般在这里就可以找到合适的结果。

            i = (i << 2) + i + perturb + 1;
            ep = &ep0[i & mask];
            if (ep->me_key == NULL) {
                if (freeslot == NULL) {
                    *value_addr = &ep->me_value;
                    return ep;
                } else {
                    *value_addr = &freeslot->me_value;
                    return freeslot;
                }
            }

    找到了unused slot的情况。 如果freeslot是NULL,那么返回该slot即可;若freeslot不是NULL,那么返回freeslot。

            if (ep->me_key == key) {
                *value_addr = &ep->me_value;
                return ep;
            }

    找到了匹配的key。此情况返回对应slot即可。

            if (ep->me_hash == hash && ep->me_key != dummy) {
                startkey = ep->me_key;
                Py_INCREF(startkey);
                cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
                Py_DECREF(startkey);
                if (cmp < 0) {
                    *value_addr = NULL;
                    return NULL;
                }
                if (ep0 == mp->ma_keys->dk_entries && ep->me_key == startkey) {
                    if (cmp > 0) {
                        *value_addr = &ep->me_value;
                        return ep;
                    }
                }
                else {
                    /* The dict was mutated, restart */
                    goto top;
                }
            }

    该slot hash值与给定hash值相同时进一步比较的情况。

            else if (ep->me_key == dummy && freeslot == NULL)
                freeslot = ep;

    在dummy情况下设置freeslot。

    在搜索过程中,原则是找到和key相等的对象即可。 那么什么是和key相等呢? 一种情况是它们的引用相等,自然的值也相等。 这类比较只需要直接比较对应指针是否相等呢该即可。 而另一种情况是引用不相等,但值还相等。 如果没有对这种情况的处理,那么对于非共享的对象来说搜索几乎不会得到正确的结果。 搜索中的进一步比较就是对这种情况的处理。 进一步比较发生的前提是hash值相等,因为值相等必然有hash相等, 但hash相等值却可能不等,因此不能直接比较hash值,还需要更进一步的比较值才可以。

  • 相关阅读:
    registration system(map+思维)
    Codeforces 158B:Taxi(贪心)
    牛客小白月赛24 B-组队(二分)
    CF58C Trees(逆向思维)
    lower_bound和upper_bound学习笔记
    POJ--2689Prime Distance(区间素数筛)
    Codeforces Round #635 (Div. 2)
    navicat premium安装,使用
    Oracel 之PL/SQL Developer使用
    PLSQL,sql语句中带有中文的查询条件查询不到数据
  • 原文地址:https://www.cnblogs.com/ruizhang3/p/6888006.html
Copyright © 2020-2023  润新知