映射(Maps)与字典(Dictionaries)

MicroPython 字典和映射使用的是被称为开放地址和线性探测的技术。这一章节将详细介绍这两种技术。

开放寻址

开放寻址 是用来解决冲突的一项技术。冲突是非常常见的情况,发生在两个项目的哈希值相同时。例如,给定一个哈希设置如下:

../_images/collision.png

如果请求填充槽 0 的值为 70,因为槽 0 不为空,开放寻址将找到下一个可用的槽来服务这个请求。这种对替代位置的顺序搜索称为 探测 。存在数种用于顺序探测的算法,但 MicroPython 使用的是线性探测,这是在下一节中描述的。

线性探测

线性探测是在字典中找到可用地址或槽的一种方法。在 MicroPython 中,它被用于开放寻址。为了服务上述描述的请求,线性探测假设每次探测的固定的间隔为 1 。请求将被放置到下一个能满足需求的空闲槽中,在我们的例子中,即槽 4

../_images/linprob.png

在字典中搜索项也是使用同样的方法,即开放寻址和线性探测。假设我们想搜索数据项 33 。计算出的哈希值将是 2 。查看槽 2 会显示 33 ,此时,我们返回 True 。搜索 70 则展现出非常不同的过程,因为在插入时发生了冲突。因为计算出的哈希值是 0 ,它当前正在保存着 44 。不过,此时我们并不是直接返回 False ,而是执行一个顺序搜索,从点 1 开始,直到找到项目 70 或遇到一个空闲槽。这是一个在哈希中执行搜索的寻常方式:

// not yet found, keep searching in this table
pos = (pos + 1) % set->alloc;

if (pos == start_pos) {
    // search got back to starting position, so index is not in table
    if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
        if (avail_slot != NULL) {
            // there was an available slot, so use that
            set->used++;
            *avail_slot = index;
            return index;
        } else {
            // not enough room in table, rehash it
            mp_set_rehash(set);
            // restart the search for the new element
            start_pos = pos = hash % set->alloc;
        }
    }
} else {
     return MP_OBJ_NULL;
}