第八章 Caché 算法与数据结构散列表
散列表
散列表也叫做哈希表,这种数据结构提供了键(key)值(value)的映射关系,只要给出一个key就可以高效查找它所匹配的value,时间复杂度接近于O(1)。
| key | value |
|---|---|
| key1 | vaule1 |
| key2 | vaule2 |
| key3 | vaule3 |
| key4 | vaule4 |
完整示例
在直接寻址的情况下,具有关键字k的元素被存储在槽k中。比方说关键字域有3,5,9,11四个数,那么它只能被存储在3,5,9,11四个位置,其他的位置全部都被浪费掉了,这时候就可以通过散列函数h,将关键字域中的元素映射到散列表[0,m-1]的位置上。
这时候内存的花销就大大的减少了。
散列函数定义为:
index=key%16;
通过链接法来解决碰撞问题:
链表节点类
Class PHA.YX.Arithmetic.HashMap.HashEntry Extends %RegisteredObject
{
Property key As %Integer;
Property value [ InitialExpression = 0 ];
Property next As HashEntry;
Property pre As HashEntry;
}
哈希表类
Class PHA.YX.Arithmetic.HashMap Extends %RegisteredObject
{
Property size As %Integer [ InitialExpression = 16 ];
Property arrayList As array Of PHA.YX.Arithmetic.HashMap.HashEntry;
Method %OnNew() As %Status [ Private, ServerOnly = 1 ]
{
f i = 0 : 1 : ..size - 1 d
.d ..arrayList.SetAt("", i)
Quit ?$OK
}
Method getContainer() As %ListOfObjects
{
q ..arrayList
}
Method getIndex(key As %Integer)
{
q key#16
}
Method insert(key As %Integer, value As %Integer) As %Boolean
{
q:..get(key)'="" ?$NO
s index = ..getIndex(key)
q:index>16 ?$NO
s ret = ?$NO
if (..arrayList.GetAt(index) = "") {
s mEntry = ##class(PHA.YX.Arithmetic.HashMap.HashEntry).%New()
s mEntry.key = key
s mEntry.value = value
d ..arrayList.RemoveAt(index)
d ..arrayList.SetAt(mEntry,key)
s ret = ?$YES
}
else {
s mEntry = ..arrayList.GetAt(index)
s preEntry = mEntry
while (mEntry '="") {
s preEntry = mEntry
s mEntry = mEntry.next
}
s newEntry = ##class(PHA.YX.Arithmetic.HashMap.HashEntry).%New()
s newEntry.pre = mEntry
s newEntry.key = key
s newEntry.value = value
s preEntry.next = newEntry
s ret = ?$YES
}
q ret
}
Method get(key As %Integer) As PHA.YX.Arithmetic.HashMap.HashEntry
{
s index = ..getIndex(key)
q:..arrayList.GetAt(index)="" ""
s ret = ""
#dim mEntry as PHA.YX.Arithmetic.HashMap.HashEntry = ..arrayList.GetAt(index)
while ((mEntry '= "")&&(ret = ""))
{
i mEntry.key = key d
.s ret = mEntry
e d
.s mEntry = mEntry.next
}
q ret
}
Method remove(key As %Integer) As %Boolean
{
s index = ..getIndex(key)
q:..arrayList.GetAt(index)="" ?$NO
#dim mEntry as PHA.YX.Arithmetic.HashMap.HashEntry = ..arrayList.GetAt(index)
while (mEntry '= ""){
if (mEntry.key = key){
if (mEntry.pre = ""){
s mEntry.value = ""
return ?$YES
}else{
s mEntry.pre = mEntry.next
return ?$YES
}
}else{
s mEntry = mEntry.next
}
}
return ?$NO
}
Method edit(key As %Integer, value As %Integer) As %Boolean
{
#dim mEntry as PHA.YX.Arithmetic.HashMap.HashEntry = ..get(key)
q:mEntry="" ?$NO
s mEntry.value = value
q ?$YES
}
}
调用
/// w ##class(PHA.YX.Arithmetic).HashMap()
ClassMethod HashMap()
{
s $zt = "ErrHashMap"
#dim mHashMap as PHA.YX.Arithmetic.HashMap = ##class(PHA.YX.Arithmetic.HashMap).%New()
d mHashMap.insert(1,2)
d mHashMap.insert(17,3)
w mHashMap.get(1),!
w mHashMap.get(17),!
w mHashMap.get(1).value,!
w mHashMap.get(17).value,!
d mHashMap.edit(1,4)
w mHashMap.get(1).value,!
w mHashMap.get(17).value,!
d mHashMap.remove(1)
w mHashMap.get(1).value,!
w mHashMap.get(17).value,!
q ""
ErrHashMap
q $ze
}
做了一个简单的碰撞测试,最后是输出结果,显然这两个地址是不一样的
DHC-APP>w ##class(PHA.YX.Arithmetic).HashMap()
3@PHA.YX.Arithmetic.HashMap.HashEntry
4@PHA.YX.Arithmetic.HashMap.HashEntry
2
3
4
3
3