希望这不是一个重复的问题。我查看并发现了类似的问题,但在这种情况下还不够。
我有许多树视图控件,并且可以出于各种原因递归遍历节点。
但是,我经常需要 遍历节点,就好像它们在列表中一样。
我想创建一个函数,从Nodes集合创建Generic.List(of TreeNode)
,如果可能的话,没有递归。
( 没有递归纯粹是为了不进行递归而不进行递归 - 我明白可能不可能)
在大规模解决方案中重复使用此函数可以节省大量时间,编码人员可以使用简单的For Each
范例遍历节点。
我已经看到了一种使用C#“扁平化”Nodes集合的技术,它使用LINQ和递归,但我不确定语法是否可以干净地转换为VB.NET。因此,如果有任何聪明的VB函数,我可以完成这项任务 - 非常有用。
在SO上有许多类似的问题和非常丰富的答案,如下所示: Enumerating Collections that are not inherently IEnumerable? ...使用某些算法突出显示非常深的树中的堆栈溢出错误。我希望不使用递归的方法不会受到堆栈溢出错误的影响 - 但是,我准备好它可能很长而且笨拙和缓慢。
我也准备好了答案'没有递归就无法做到这一点'。但是,我想使用SO(本论坛)
的力量来确认或否认这一主张答案 0 :(得分:2)
这是可能的,而且根本不是很难......
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TreeView1.ExpandAll()
For Each TN As TreeNode In TreeView1.NodesToListWithoutRecursionBecauseWhyNot(TraverseType.BreadthFirst)
Debug.Print(TN.Text)
Next
End Sub
End Class
Public Module Extensions
Public Enum TraverseType
BreadthFirst
DepthFirst
End Enum
<Runtime.CompilerServices.Extension()> _
Public Function NodesToListWithoutRecursionBecauseWhyNot(ByVal TV As TreeView, Optional ByVal Traverse As TraverseType = TraverseType.DepthFirst) As List(Of TreeNode)
Dim nodes As New List(Of TreeNode)
Select Case Traverse
Case TraverseType.BreadthFirst
Dim Q As New Queue(Of TreeNode)
For Each TN As TreeNode In TV.Nodes
Q.Enqueue(TN)
Next
While Q.Count > 0
Dim TN As TreeNode = Q.Dequeue
nodes.Add(TN)
For Each subTN As TreeNode In TN.Nodes
Q.Enqueue(subTN)
Next
End While
Case TraverseType.DepthFirst
Dim L As New List(Of TreeNode)
For Each TN As TreeNode In TV.Nodes
L.Add(TN)
Next
While L.Count > 0
Dim TN As TreeNode = L.Item(0)
L.RemoveAt(0)
nodes.Add(TN)
For i As Integer = TN.Nodes.Count - 1 To 0 Step -1
L.Insert(0, TN.Nodes(i))
Next
End While
End Select
Return nodes
End Function
End Module
答案 1 :(得分:1)
只需将节点添加到列表中,但同时保持您处理的最后一个节点的位置。当一个节点的直接子节点被添加到列表中时,该节点被视为进程。
Public Function GetAllNodes(ByVal topNode As TreeNode)
Dim allNodes As New List(Of TreeNode)
Dim lastProcessPosition As Integer = 0
allNodes.Add(topNode)
Do While lastProcessPosition < allNodes.Count
allNodes.AddRange(allNodes(lastProcessPosition).Nodes)
lastProcessPosition += 1
Loop
Return allNodes
End Function
如果您没有顶级节点,那么只需将该参数替换为开始的节点列表。
Public Function GetAllNodes(ByVal topNodes As TreeNodeCollection)
Dim allNodes As New List(Of TreeNode)
Dim lastProcessPosition As Integer = 0
allNodes.AddRange(topNodes)
Do While lastProcessPosition < allNodes.Count
allNodes.AddRange(allNodes(lastProcessPosition).Nodes)
lastProcessPosition += 1
Loop
Return allNodes
End Function
我不确定在使用Nodes属性之前是否必须检查Nothing。
注意:我能够删除此for循环并将其替换为AddRange
'For Each node As TreeNode In allNodes(lastProcessPosition).Nodes
' allNodes.Add(node)
'Next