散列学习(二)

来源:互联网 发布:音乐剪切合并软件 mac 编辑:程序博客网 时间:2024/05/23 18:31

二、线性探测法散列表:用大小为M的数组保存N个键值对。

1特点:

1)、M>N

2)、需要依靠数组中的空位解决碰撞冲突。

基于这种策略的所有方法统称为开放地址散列表。

开放地址散列表中最简单的方法叫做线性探测法:碰撞发生时,直接检查散列表中的下一个位置。

2线性探测会产生三种结果:

1)、命中:该位置的键和被查找的键相同;

2)、未命中:该位置键为空(该位置没有使用,故被查找的键在散列中不存在)

3)、继续查找:该位置键不为空,且与被查找的键不同。

3查找步骤:

1)、用散列函数找到该键在数组中的索引;

2)、检查其中的键和被查找的键是否相同;

3)、键不同,则索引递增(到大数组结尾时折回数组开头),继续查找。

4)、终止查找条件:找到该键或遇到一个空元素。

4开放地址散列表的核心思想:

与其将内存用作链表,不如将内存作为散列的空元素。这些空元素可以作为查找结束的标志。

5删除操作:

由于线性探测散列表搜索遇到keynull时就结束,因而删除线性探测散列表中的一个键时,不能将该键设置为null。如果设置为null,则在该位置之后的元素将无法被查找。

pythondict类型就是使用开放地址散列表,它将每个(keyval)的组合成为一个entry。其结构是:

[dictobject.h]

typedefstruct{

Py_ssize_tme_hash;

PyObject*me_key;

PyObject*me_value;

}PyDictEntry;

其中me_hash字段存储的是me_key的散列值,利用一个字段记录这个散列值可以避免每次查询时都要重新计算一遍散列值。

PyDictObject对象发生变化时,entry会在不同状态间转换。entry有三种状态:Unused态、Active态和Dummy态。

当一个entryme_keyme_value都是NULL时,entry处于Unused态。Unused态表明目前该entry中并没有存储(keyvalue)对,而且在此之前,也没有存储过它们。每一个entry在初始化时都会处于这种状态,而且只有在Unused态下,entryme_key字段才会为NULL

entry中存储了一个(keyval)对时,entry便转换到了Active态。在Active态下,me_keyme_value都不能为NULL

entry中存储的(keyvalue)对被删除后,entry的状态不能直接从Active态转换为Unused态,否则将导致冲突探测链的中断。相反,entry中的me_key将指向dummy对象,entry进入Dummy态,这就是python的“伪删除”技术。当python沿着某条冲突链搜索时,如果发现一个entry处于Dummy态,说明目前该entry虽然是无效的,但是其后的entry可能是有效的,应该继续搜索,这样就保证了冲突探测链的连续性。

6、键簇:

线性探测的平均成本取决于元素插入数组后聚集成的一组连续的条目,称为键簇。当新keyhash值与已经插入散列表中元素的hash值冲突时,线性探测要探测从该hash值向后组成的键簇的所有位置,因而,短小的键簇才能保证较高的效率。由于均匀性假设,数组每个位置都有相同的可能被插入一个新的键,因而长键簇更长的可能性比短键簇更大。

7、调整数组的大小:

命题M(此处只取其结论)表明:当散列表快满时,需要探测的次数是巨大的,当散列表使用率小于1/2时,探测的预计次数只在1.52.5之间。因而,在实际应用时应考虑动态调整散列表数组的大小,确保数组的使用率永远都不会超过1/2

0 0
原创粉丝点击