2015-01-26 2 views
1

Надеюсь, это не повторный вопрос. Я посмотрел и нашел похожие вопросы, но в этом случае недостаточно. У меня есть много элементов управления представлением дерева, и можно рекурсивно пересекать узлы по разным причинам. Однако мне часто приходится проходить через узлы, как если бы они были в списке. Я хотел бы создать функцию, которая создает Generic.List(of TreeNode) из коллекции Nodes, без рекурсии, если это вообще возможно.Сбор узлов сборных деревьев в список без рекурсии

(без рекурсии чисто для осуществления делать это без рекурсии - Я понимаю, что может не возможно)

Эта функция позволит сэкономить много времени при повторном использовании через массивным раствор, где кодеры могли использовать простую парадигму For Each для перемещения узлов.

Я видел технику «сплющить» коллекцию Nodes, используя C#, которая использует LINQ и рекурсию, но я не уверен, что синтаксис может быть преобразован в VB.NET. Поэтому, если есть какие-то умные функции VB, я могу сделать это для этой задачи - было бы очень полезно.

Есть много подобных вопросов и очень информативные ответы на SO, как этот: Enumerating Collections that are not inherently IEnumerable? ... который выдвигает на первый план стека ошибок переполнения в очень глубоких деревьев с помощью некоторых алгоритмов. Я надеюсь, что метод, который не использует рекурсию, не пострадает от ошибок переполнения стека, однако я готов, чтобы он был длинным, неуклюжим и медленным.

Я также готов ответить, что 'Это невозможно сделать без рекурсии'. Тем не менее, я хотел бы подтвердить или опровергнуть это утверждение, используя силу SO (этот форум)

+0

Вы говорите, что вы уже знаете, как читать через 'управления TreeView' найти все узлы, так почему не может вы просто создаете список с результатами? Неясно, в какой части задачи вы столкнулись. –

+0

@StevenDoggart Спасибо, да, я могу пройти и построить список, используя рекурсию. В вопросе предполагается выделить «нет рекурсии» - если это вообще возможно. – Grantly

+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 
+0

Очень приятно. Не так неуклюже, как я ожидал! – Grantly

+0

Теперь вы можете сначала указать ширину или глубину. –

+0

LOL, мне нравится ваше улучшение и дополнительная полезность. (LOL, как вам кажется, кодер, который любит расширять, чтобы сделать по-настоящему мощную функцию) – Grantly

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.

Примечание: Я был в состоянии удалить этот цикл и заменить его AddRange

'For Each node As TreeNode In allNodes(lastProcessPosition).Nodes 
' allNodes.Add(node) 
'Next 
+0

Спасибо, это выглядит очень аккуратно. Попробуйте несколько секунд, чтобы проверить его, но он выглядит очень хорошо – Grantly

+0

@ Grantly Я удалил For For и заменил его AddRange –

+0

Хорошее улучшение. Приветствия. Очень эффективный и аккуратный – Grantly

Смежные вопросы