ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[原创] VBA编程技巧 之 不用字典、集合实现联动菜单 及 简易字典功能的实现

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2014-12-9 16:37 | 显示全部楼层 |阅读模式
本帖已被收录到知识树中,索引项:数组集合和字典
本帖最后由 lee1892 于 2014-12-10 14:30 编辑

本贴附件: 不用字典、集合实现联动菜单 及 简易字典功能的实现 by Lee1892.rar (18.43 KB, 下载次数: 369)
修订附件: 不用字典、集合实现联动菜单 及 简易字典功能的实现 v1.0 by Lee1892.rar (23.17 KB, 下载次数: 623)

坛子里介绍如何实现联动菜单的贴子不少了,我自己就写过蛮多的,现在回头看以前的那个字典套字典的贴子都犯晕

本贴附件效果:
不用字典.gif

这里介绍一个使用简易字典功能实现的办法,采用的是除余法,字典功能的实现只是简单的一个函数,如下:
  1. Private lngCount        As Long     ' 字典项目计数
  2. Private arrKeys()       As String   ' 字典的关键字数组, 树结构中节点的由根节点开始的全路径
  3. Private arrItems()      As String   ' 字典的项目数组, 树结构中该节点下的子节点名以逗号连接

  4. Private lngCollision    As Long     ' 哈希表位置碰撞计数
  5. Private lngTableSize    As Long     ' 哈希表大小
  6. Private arrHashTable()  As Long     ' 哈希表数组, 下标为关键字计算所得的值, 值为该关键字对应的序号

  7. Private Function GetIndex&(sPath$, Optional IsNewItem As Boolean = False)
  8.     Rem IsNewItem = True,  返回新项目在哈希表中的位置
  9.     Rem IsNewItem = False, 返回字符串对应的序号
  10.     Dim i&, aStr() As Byte, nStrKey&, nHashInd&
  11.     Const LNG_SEED_1& = 113
  12.     Const LNG_SEED_2& = 601
  13.     Const LNG_SEED_3& = 71
  14.     Const LNG_SEED_4& = 137
  15.     Const LNG_MODE& = 470011
  16.     Const LNG_PRIME& = 3571
  17.     Rem 计算字符串特征值
  18.     aStr = sPath
  19.     For i = 0 To 2 * Len(sPath) - 1 Step 2
  20.         nStrKey = (nStrKey * LNG_SEED_1 + CLng(aStr(i)) * LNG_SEED_2) Mod LNG_MODE
  21.         nStrKey = (nStrKey * LNG_SEED_3 + CLng(aStr(i + 1)) * LNG_SEED_4) Mod LNG_MODE
  22.     Next
  23.     Rem 由特征值计算哈希表中位置
  24.     nHashInd = nStrKey * LNG_PRIME Mod lngTableSize + 1 ' 哈希表数组下标由 1 开始
  25.     Rem 处理哈希表位置碰撞
  26.     Do
  27.         Rem 如果该位置未被占用,则如为查询新项目在哈希表中的位置则返回该位置否则返回零
  28.         If arrHashTable(nHashInd) = 0 Then GetIndex = IIf(IsNewItem, nHashInd, 0): Exit Do
  29.         If IsNewItem Then
  30.             Rem 对哈希表位置碰撞计数
  31.             lngCollision = lngCollision + 1
  32.             Debug.Print Format(lngCollision, "000: ");
  33.             Debug.Print sPath
  34.             Debug.Print String(5, " "); arrKeys(arrHashTable(nHashInd))
  35.         Else
  36.             Rem 对比该位置对应的关键字是否与输入字符串相同,相同则返回哈希表中该位置的值
  37.             If Len(sPath) = Len(arrKeys(arrHashTable(nHashInd))) Then
  38.                 If sPath = arrKeys(arrHashTable(nHashInd)) Then GetIndex = arrHashTable(nHashInd): Exit Do
  39.             End If
  40.         End If
  41.         Rem 产生哈希表位置碰撞,位置向后挪一位查询
  42.         nHashInd = nHashInd + 1
  43.         If nHashInd > lngTableSize Then nHashInd = 1
  44.     Loop
  45. End Function
复制代码

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2014-12-9 17:10 | 显示全部楼层
感谢分享,下载学习了!

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-12-10 14:29 | 显示全部楼层
修订了字典功能的实现方法,添加了新附件,并加了注释。

字典功能实现的函数放在顶楼了。

1.0版的读取数据初始化过程为:
  1. Private Sub Initialize()
  2.     Dim aData, i&, j&, k&, nRows&, nCols&, nInd&, nParent&
  3.     Dim sNode$, sPath$, nHashInd&
  4.     Rem 读取原始数据
  5.     aData = shtData.Range("A1").CurrentRegion
  6.     nRows = UBound(aData): nCols = UBound(aData, 2)
  7.    
  8.     lngLayer = nCols                        ' 总层数等于列数
  9.     lngCount = 0                            ' 字典项目计数初值
  10.     lngCollision = 0                        ' 哈希表位置碰撞次数初值
  11.    
  12.     ReDim arrItems(-1 To nRows * nCols)     ' 预设字典项目数组,  -1 为根节点,0 留空
  13.     ReDim arrKeys(-1 To nRows * nCols)      ' 预设字典关键字数组,-1 为根节点,0 留空
  14.    
  15.     lngTableSize = nRows * nCols * 2        ' 哈希表大小为预设数组的 2 倍
  16.     ReDim arrHashTable(1 To lngTableSize)   ' 初始化哈希表
  17.    
  18.     arrHashTable(GetIndex("-", True)) = -1  ' 根节点命名 并 添加到哈希表中
  19.     arrKeys(-1) = "-"                       ' 添加根节点关键字
  20.    
  21.     Rem 数据特征为每行中各列由前到后为树结构中的完整节点路径
  22.     Rem 按先列后行扫描, 即列循环在行循环内部
  23.     For i = 2 To nRows
  24.         sPath = ""      ' 路径初值为空
  25.         nParent = -1    ' 父节点初值为根节点
  26.         For j = 1 To nCols
  27.             sNode = aData(i, j)             ' 节点名
  28.             sPath = sPath & "-" & sNode     ' 节点全路径
  29.             nInd = GetIndex(sPath)          ' 获得以全路径为关键字的序号
  30.             If nInd = 0 Then
  31.                 Rem 该关键字不在哈希表中
  32.                 lngCount = lngCount + 1     ' 字典计数
  33.                 nInd = lngCount             ' 关键字序号
  34.                 arrHashTable(GetIndex(sPath, True)) = nInd
  35.                                             ' 添加该序号到哈希表中
  36.                 arrKeys(nInd) = sPath       ' 添加到关键字数组
  37.                 Rem 将当前节点名添加到父节点的项目数组中
  38.                 If Len(arrItems(nParent)) > 0 Then
  39.                     arrItems(nParent) = arrItems(nParent) & "," & sNode
  40.                 Else
  41.                     arrItems(nParent) = sNode
  42.                 End If
  43.             End If
  44.             nParent = nInd                  ' 下一列的父节点为当前节点
  45.         Next
  46.     Next
  47.     ReDim Preserve arrItems(-1 To lngCount)
  48.     ReDim Preserve arrKeys(-1 To lngCount)
  49. End Sub
复制代码

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2014-12-11 22:03 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
向老师学习,应用实例对初学者实在是太有用了。还加了注释,谢谢分享!

TA的精华主题

TA的得分主题

发表于 2015-7-19 10:57 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2016-12-1 14:28 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2018-3-10 18:10 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2018-11-25 10:18 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2019-4-19 15:40 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
谢谢,下来学习

TA的精华主题

TA的得分主题

发表于 2019-8-1 08:55 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
先打卡,后面慢慢啃,感觉有点难懂
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

关闭

最新热点上一条 /1 下一条

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

GMT+8, 2024-4-23 18:39 , Processed in 0.054219 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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