|
楼主 |
发表于 2012-12-19 15:14
|
显示全部楼层
本帖最后由 lee1892 于 2012-12-22 13:38 编辑
迭代与递归的使用
1、本贴使用案例的原始数据分析:
此贴中所使用的案例是一个BOM清单,每一条记录反映了一个 产品/部件 所需要的一种 材料 的信息,包括如名称、规格、数量等。
该案例的最初的功能述求是取得某个 产品 所需的全部 部件 和 材料 信息,并罗列出来。显然这些数据的内在关联是一种树形结构,每个产品是一棵树,其根是产品,部件则是分支节点,材料则是叶子。
注:本贴所有代码,均假设原始数据中没有产生循环。
本贴中使用aData数组来缓存原始数据,作为数据存储的模拟,行号则模拟了储存地址,列号对应的是储存的不同信息。
让我们分别使用迭代和递归的思维逻辑来作这个查询。
2、迭代:
具体代码见一楼附件:BOM查询-不构造任何数据结构,迭代循环查询
其中获得材料信息函数GetBOMList不作详细介绍,着重讲迭代过程,代码如下:
[code=vb]
Private Sub GetChildren(sNo$, aRows, nCount&, iLayer&)
' sNo: 产品/部件 的编号,对应于 GC 列,过程内改变值,应定义为 ByRef
' aRows: 二维数组,用于保存查找的结果,第二维对应的是查找到的项目数量,第一维有2个元素分别对应该项的层数和地址,过程内改变,应定义为 ByRef
' nCount: 查找得到结果的数量,过程内改变,应定义为 ByRef
' iLayer: 查找得到结果的层数,由于是迭代过程,这个参数实际为内部变量,为不改变其它代码,故作保留
' 以上参数中,aRows实际上是返回值。
Dim i&, nCurrent&
iLayer = 1 ' 初始化层数为 1
Do
' 循环查找,退出机制使用Exit Do方式设于循环内部
For i = 2 To UBound(aData)
' 遍历数据,进行查找。递归的结束是查找完全部数据。
If sNo = aData(i, nParentCol) Then
' 于GC列,找到 产品/部件 的编号
nCount = nCount + 1 ' 找到的项目数量 +1
aRows(1, nCount) = iLayer ' 在返回数组中记录该项目的层数
aRows(2, nCount) = i ' 在返回数组中记录该项目的地址
End If
Next
nCurrent = nCurrent + 1 ' 在查找到的结果中,下次循环查找项目指针 +1
If nCurrent > nCount Then Exit Do ' 如果下次查找项目指针大于已经找到的项目数量,则完成全部查询,退出
sNo = aData(aRows(2, nCurrent), nItemCol) ' 获得下次查询的 部件/材料 编号
iLayer = aRows(1, nCurrent) + 1 ' 下次查询的层数 是 本次查询的层数 +1
Loop
End Sub
[/code]
由于上述迭代查询代码的限制,显示的查询结果是按层数排列的,即总是低层的在前面。
3、递归:
具体代码见一楼附件:BOM查询-不构造任何数据结构,递归循环查询
[code=vb]
Private Sub GetChildren(sNo$, aRows, nCount&, iLayer&)
' sNo: 产品/部件 的编号,对应于 GC 列,过程内不改变值,可定义为 ByVal
' aRows: 二维数组,用于保存查找的结果,第二维对应的是查找到的项目数量,第一维有2个元素分别对应该项的层数和地址,过程内改变,应定义为 ByRef
' nCount: 查找得到结果的数量,过程内改变,应定义为 ByRef
' iLayer: 查找得到结果的层数,过程内改变,应定义为 ByRef
' 以上参数中,aRows实际上是返回值。
Dim i&, sItemNo$ ' , nRow&, nChildNodeNo& 这俩变量忘删了...
For i = 2 To UBound(aData)
' 遍历数据,进行查找。递归的结束是查找完全部数据。
If sNo = aData(i, nParentCol) Then
' 于GC列,找到 产品/部件 的编号
iLayer = iLayer + 1 ' 层数 +1
nCount = nCount + 1 ' 找到的项目数量 +1
aRows(1, nCount) = iLayer ' 在返回数组中记录该项目的层数
aRows(2, nCount) = i ' 在返回数组中记录该项目的地址
sItemNo = aData(i, nItemCol) ' 获得该项目的 部件/材料 编号
Call GetChildren(sItemNo, aRows, nCount, iLayer) ' 对该项目的 部件/材料 编号进行查找
End If
Next
iLayer = iLayer - 1 ' 本次数据遍历查找结束,层数 -1
End Sub
[/code]
由于采用递归的方法,每次查询树的分支情况时,总是在到达叶子后才返回,所以查询得到的结果是也是同样的顺序,即按 部件/材料 的从属关系排列的。
=======================================================
Original Post (原有用数组构造双向链表的ParseData代码,删,详见1楼附件)
改写成用数组构造双向链表,貌似初始化的速度快了很多啊,而且内存占用也很小
看来字典多重嵌套不是什么好办法,应该尽量少用。。。
附件在1楼
|
|