ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: Zamyi

[分享] 哈希表原理和实现

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2018-3-21 10:11 | 显示全部楼层
有空的时候琢磨一下,谢谢分享了

TA的精华主题

TA的得分主题

发表于 2018-3-22 13:15 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
收藏学习了........

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-4-5 21:23 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
高度保密 发表于 2018-3-20 00:50
64位中这个StrPtr数据类型不匹配怎么解决呢

试试
  1. Private Declare PtrSafe Function hash Lib "ntdll.dll" Alias "RtlComputeCrc32" (ByVal start As Long, ByVal data As Long, ByVal Size As Long) As Long
  2. Private Hash_Table() As Long           '哈希表
  3. Private Count_Table As Long            '哈希表大小
  4. Private H As Long                      '哈希值
  5. Public Count As Long                   'Keys实际数目

  6. Public Sub Init(bCount&)  '初始化哈希表
  7. Count = 0
  8. Count_Table = bCount * 1.33
  9. ReDim Hash_Table(Count_Table - 1)
  10. End Sub

  11. Public Function Add(Key, Keys, x&) As Boolean
  12. Dim k As Long, P
  13. P = StrPtr(Key)
  14. H = (hash(0, P, LenB(Key)) And &H7FFFFFFF) Mod Count_Table
  15. Do
  16.   If Hash_Table(H) = 0 Then
  17.     Count = Count + 1
  18.     Hash_Table(H) = Count
  19.     Keys(Hash_Table(H), x) = Key
  20.     Add = True
  21.     Exit Function
  22.   End If
  23.   If StrComp(Key, Keys(Hash_Table(H), x)) = 0 Then Exit Function
  24.   k = k + 1
  25.   H = (H + k * k) Mod Count_Table
  26. Loop
  27. End Function

  28. Public Function GetX(Key, Keys, x&) As Long
  29. Dim k As Long, P
  30. P = StrPtr(Key)
  31. H = (hash(0, P, LenB(Key)) And &H7FFFFFFF) Mod Count_Table
  32. Do
  33.   If Hash_Table(H) = 0 Then Exit Function
  34.   If StrComp(Key, Keys(Hash_Table(H), x)) = 0 Then GetX = Hash_Table(H): Exit Function
  35.   k = k + 1
  36.   H = (H + k * k) Mod Count_Table
  37. Loop
  38. End Function
复制代码

TA的精华主题

TA的得分主题

发表于 2018-4-7 20:38 | 显示全部楼层
本帖最后由 高度保密 于 2018-4-9 22:37 编辑

可以了,谢谢!
不过您的字典,在下面的附件中,这一句:        n = ds(Arr(i, 1))
会出现对象不支持该属性的问题,不知道能不能优化一下
Zamyi字典.PNG
Zamyi的字典.rar (16.52 KB, 下载次数: 21)

TA的精华主题

TA的得分主题

发表于 2018-4-7 22:42 | 显示全部楼层
明白了
hash(0, StrPtr(Key), LenB(Key)这句是关键,以前没见过
取余数是为了索引号在数组下标内但这样会出现重复,用H = (H + k * k)来改变索引
* 1.33是为什么,是估计的还是有什么道理,如果恰巧Do好多次后k = k + 1 k * k 得到的H有没有超出范围的可能。

谢谢楼主分享!

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-4-8 14:17 | 显示全部楼层
高度保密 发表于 2018-4-7 20:38
可以了,谢谢!
不过您的字典好像也有在64位excel也有兼容性问题,不知道能不能优化一下

手头没有64位Office测试,自己修改。调用Dll主要二点
1、声明Declare注意加上 PtrSafe,
2、StrPtr返回的是LongLong类型,需转换成Long型。

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-4-8 14:30 | 显示全部楼层
HHAAMM 发表于 2018-4-7 22:42
明白了
hash(0, StrPtr(Key), LenB(Key)这句是关键,以前没见过
取余数是为了索引号在数组下标内但这样会 ...

哈希查找实际是查找哈希表中未使用的位置(称之为空穴),以随机样本,空穴比例小于25%时查找的效率降低较大,所以最小取1.33(1/1.33≈0.75)。改变H值上面所说的应该是固定种子随机数更能保证不会超出范围,但随机数毕竟也耗费资源;固定长度对于数量大明显效率降低,灰袍法师和老窖字典用的是固定定长;用平方序列,会比固定定长效果好些。除非是刻意地构造数据,绝大多数情况下应该不会超出范围。

TA的精华主题

TA的得分主题

发表于 2018-4-8 18:07 | 显示全部楼层
  1. Sub test()
  2.     Dim A As Variant
  3.     Dim B() As String
  4.     Dim HT() As Long, I(1 To 2) As Long, C As Long, R As Long, Y As Long, X As Long, H As Long, J As Long, P As Long
  5.     A = Sheet1.Range("a1", Sheet1.[b65536].End(3))
  6.     R = UBound(A)
  7.     C = R * 1.33
  8.     ReDim B(1 To R, 1 To 3)
  9.     For X = 1 To 2
  10.         ReDim HT(C - 1)
  11.         For Y = 1 To R
  12.             P = 0
  13.             H = (hash(0, StrPtr(A(Y, X)), LenB(A(Y, X))) And &H7FFFFFFF) Mod C
  14.             Do
  15.                 If HT(H) = 0 Then
  16.                     I(X) = I(X) + 1
  17.                     HT(H) = I(X)
  18.                     B(HT(H), X) = A(Y, X)
  19.                     Exit Do
  20.                 ElseIf StrComp(A(Y, X), B(HT(H), X)) = 0 Then
  21.                     Exit Do
  22.                 Else
  23.                     P = P + 1
  24.                     H = (H + P * P) Mod C
  25.                 End If
  26.             Loop
  27.         Next
  28.     Next
  29.     For Y = 1 To I(1)
  30.         P = 0
  31.         H = (hash(0, StrPtr(B(Y, 1)), LenB(B(Y, 1))) And &H7FFFFFFF) Mod C
  32.         Do
  33.             If HT(H) = 0 Then
  34.                 Exit Do
  35.             ElseIf StrComp(B(Y, 1), B(HT(H), 2)) = 0 Then
  36.                 J = J + 1
  37.                 B(J, 3) = B(Y, 1)
  38.                 Exit Do
  39.             Else
  40.                 P = P + 1
  41.                 H = (H + P * P) Mod C
  42.             End If
  43.         Loop
  44.     Next
  45.     Sheet1.Range("c1:e" & R) = B
  46. End Sub
  47. '弄成这样好理解些
复制代码

TA的精华主题

TA的得分主题

发表于 2018-4-9 22:40 | 显示全部楼层
Zamyi 发表于 2018-4-8 14:30
哈希查找实际是查找哈希表中未使用的位置(称之为空穴),以随机样本,空穴比例小于25%时查找的效率降低 ...

我将哈希表最大下标扩大很多,用一百万行数据测试,运行速度反而快不少。
* 20

TA的精华主题

TA的得分主题

发表于 2018-4-9 22:53 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
谢谢楼主,收藏学习了........
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-5-20 18:56 , Processed in 0.046418 second(s), 6 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表