├── .gitignore ├── LICENSE ├── MeasureTree_64x.png ├── README.md └── source ├── CleanAll.bat ├── Shared ├── BreadthFirst │ ├── LevelOrder.cs │ ├── TraverseLevelOrder.cs │ └── TraverseLevelOrderEnumerableRoot.cs ├── Depthfirst │ ├── PostOrder.cs │ ├── PreOrder.cs │ ├── TraversePostOrder.cs │ ├── TraversePostOrderEnumerableRoot.cs │ ├── TraversePreorder.cs │ └── TraversePreorderEnumerableRoot.cs ├── Models │ └── LevelOrderCursor.cs ├── Shared.projitems └── Shared.shproj ├── TreeLib ├── Readme.txt └── TreeLib.csproj ├── TreeLibDemo.sln ├── TreeLibDemo ├── App.config ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── TreeLibDemo.csproj ├── TreeLibDemoLib ├── Development │ ├── LevelOrderV1.cs │ ├── LevelOrderV2.cs │ ├── PostOrderV1.cs │ ├── PostOrderV2.cs │ ├── PreOrderV1.cs │ └── PreOrderV2.cs ├── Node.cs ├── Properties │ └── AssemblyInfo.cs └── TreeLibDemoLib.csproj ├── TreeLibNet ├── Properties │ └── AssemblyInfo.cs └── TreeLibNet.csproj ├── TreeLibNugetDemo ├── App.config ├── Demos │ ├── Directories │ │ ├── DirSizeWoException.cs │ │ └── DirectorySize.cs │ ├── Node.cs │ ├── PrintMenu.cs │ └── TraversalDemo.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── TreeLibNugetDemo.csproj └── packages.config └── TreeLibNugetUnitTests ├── CoreTests.cs ├── Properties └── AssemblyInfo.cs ├── TreeLibNugetUnitTests.csproj └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | source/packages/ 2 | packages/ 3 | 00_Release/ 4 | 01_Nuget/ 5 | debug/ 6 | release/ 7 | build/ 8 | bin/ 9 | obj/ 10 | cache/ 11 | log/ 12 | tmp/ 13 | /source/.vs/ 14 | .vs/ 15 | 16 | *~ 17 | *.lock 18 | *.DS_Store 19 | *.swp 20 | *.out 21 | *.sou 22 | *.suo 23 | *.sqlite 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MeasureTree_64x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dirkster99/TreeLib/fd61f291f53df9a8d8d101f8ce246fb929466d90/MeasureTree_64x.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://ci.appveyor.com/api/projects/status/de18xc6i431xnlvg?svg=true)](https://ci.appveyor.com/project/Dirkster99/treelib) 2 | [![Release](https://img.shields.io/github/release/Dirkster99/TreeLib.svg)](https://github.com/Dirkster99/TreeLib/releases/latest) 3 | [![NuGet](https://img.shields.io/nuget/dt/Dirkster.TreeLib.svg)](http://nuget.org/packages/Dirkster.TreeLib) 4 | 5 | # TreeLib 6 | This project provides a: 7 | - .Net Standard Library (1.4, 1.6, 2.0) or a 8 | - .Net framework 4.0 Library 9 | 10 | with Generic methods to traverse k-ary trees in different orders (Post-Order, Pre-Order, Level-Order) of traversal. This implementation includes scalable algorithms that return `IEnumerable` to make parsing large tree structures a piece of cake, as well, as [Generic Exception handling](https://github.com/Dirkster99/TreeLib/blob/adb9145b9c5baaf0ee8bd6f5fe5982354d962dc2/source/TreeLibNugetDemo/Demos/Directories/DirectorySize.cs#L85-#L86) to ensure that traversal algorithms complete despite unexpected errors on some nodes. 11 | 12 | Review demo projects: 13 | * in this solution, 14 | * WPF FilterTreeView sample application, and read 15 | * Advanced WPF TreeViews Part 3 of n 16 | * Advanced WPF TreeViews Part 4 of n to learn more details. 17 | 18 | Implementing something as complicated as a Post-Order traversal algorithm requires just: 19 | * a project reference, 20 | * a LINQ statement to find each set of children in the tree, 21 | * and a simple for each loop to implement the operation on each tree node: 22 | 23 | ```C# 24 | Console.WriteLine("(Depth First) PostOrder Tree Traversal V3"); 25 | items = TreeLib.Depthfirst.Traverse.PostOrder(root, i => i.Children); 26 | 27 | foreach (var item in items) 28 | { 29 | Console.WriteLine(item.GetPath()); 30 | } 31 | ``` 32 | This pattern leads to a clear-cut separation of: 33 | * the traversal algorithm and 34 | * the operations performed on each tree node (e.g.: `Console.WriteLine(item.GetPath());`). 35 | 36 | The project in this repository contains a demo console project to demo its usage in more detail. 37 | 38 | # Supported Generic Traversal Methods 39 | 40 | ## Breadth First 41 | ### Level Order 42 | See TreeLib.BreadthFirst.Traverse.LevelOrder implementation for: 43 | 44 | * Trees with 1 root node (expects 1 <T> root item as parameter) 45 | * Trees with multiple root nodes (expects an IEnumerable<T> root item as parameter) 46 | * Generic Level-Order function and DemoDirectoryTreeTraversal 47 | 48 | ## Depth First 49 | ### PreOrder 50 | See TreeLib.BreadthFirst.Traverse.PreOrder implementation for: 51 | 52 | * Trees with 1 root node (expects 1 <T> root item as parameter) 53 | * Trees with multiple root nodes (expects IEnumerable<T> root as parameter) 54 | * Generic Pre-Order function and DemoDirectoryTreeTraversal 55 | 56 | ### Postorder 57 | See TreeLib.BreadthFirst.Traverse.Postorder implementation for: 58 | 59 | * Trees with 1 root node (expects 1 <T> root item as parameter) 60 | * Trees with multiple root nodes (expects IEnumerable<T> root item as parameter) 61 | * Generic Post-Order function and DemoDirectoryTreeTraversal 62 | 63 | # Tip 64 | * Read about [Generic Tree and Linked List Traversal in C#](http://web.archive.org/web/20180128233111/http://www.codeducky.org/easy-tree-and-linked-list-traversal-in-c/) to understand the usefulness of *Generic* traversal methods. 65 | 66 | * Watch the Binary tree traversal: Preorder, Inorder, Postorder video to better understand what is what (and why these Traversal Order Names make some sense): 67 | 68 | * Look into data structure books online [Introduction to Trees, Binary Search Trees](https://cathyatseneca.gitbooks.io/data-structures-and-algorithms/introduction_to_trees,_binary_search_trees/definitions.html) or offline *[Algorithms](http://algs4.cs.princeton.edu/home/)* by Robert Sedgewick and Kevin Wayne, if you still need more background on tree structures 69 | -------------------------------------------------------------------------------- /source/CleanAll.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | pushd "%~dp0" 3 | ECHO. 4 | ECHO. 5 | ECHO. 6 | ECHO This script deletes all temporary build files in the .vs folder and the 7 | ECHO BIN and OBJ folders contained in the following projects 8 | ECHO. 9 | ECHO TreeLibNugetDemo 10 | ECHO TreeLibDemo 11 | ECHO TreeLib 12 | ECHO TreeLibNet 13 | ECHO. 14 | REM Ask the user if hes really sure to continue beyond this point XXXXXXXX 15 | set /p choice=Are you sure to continue (Y/N)? 16 | if not '%choice%'=='Y' Goto EndOfBatch 17 | REM Script does not continue unless user types 'Y' in upper case letter 18 | ECHO. 19 | ECHO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 20 | ECHO. 21 | ECHO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 22 | ECHO. 23 | ECHO Removing vs settings folder with *.sou file 24 | ECHO. 25 | RMDIR /S /Q .vs 26 | 27 | ECHO. 28 | ECHO Deleting BIN and OBJ Folders in TreeLibNugetDemo 29 | ECHO. 30 | RMDIR /S /Q "TreeLibNugetDemo\bin" 31 | RMDIR /S /Q "TreeLibNugetDemo\obj" 32 | 33 | ECHO. 34 | ECHO Deleting BIN and OBJ Folders in TreeLibDemo 35 | ECHO. 36 | RMDIR /S /Q "TreeLibDemo\bin" 37 | RMDIR /S /Q "TreeLibDemo\obj" 38 | 39 | ECHO. 40 | ECHO Deleting BIN and OBJ Folders in TreeLib 41 | ECHO. 42 | RMDIR /S /Q "TreeLib\bin" 43 | RMDIR /S /Q "TreeLib\obj" 44 | 45 | ECHO. 46 | ECHO Deleting BIN and OBJ Folders in TreeLibNet 47 | ECHO. 48 | RMDIR /S /Q "TreeLibNet\bin" 49 | RMDIR /S /Q "TreeLibNet\obj" 50 | 51 | PAUSE 52 | 53 | :EndOfBatch 54 | -------------------------------------------------------------------------------- /source/Shared/BreadthFirst/LevelOrder.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLib.BreadthFirst 2 | { 3 | using System; 4 | using System.Linq; 5 | using System.Collections.Generic; 6 | 7 | /// 8 | /// Implements a Generic class that can traverse a tree with tree nodes of type 9 | /// and supports invoking calls on each node via 10 | /// Generic method in the Traversal method. 11 | /// 12 | /// 13 | /// 14 | public class LevelOrder 15 | { 16 | /// 17 | /// http://urosv.blogspot.de/2011/04/iterative-binary-tree-traversal.html 18 | /// C/C++ Blog Post by: Uros Vidojevic 19 | /// 20 | /// Levelorder traversal implementation is very similar 21 | /// to the preorder implementation, with the most significant difference 22 | /// that the is used instead of a 23 | /// . 24 | /// 25 | /// This object points at the root of the tree structure. 26 | /// This Generic method implements a way of enumerating all 27 | /// childrens for the root or current node in the traversal. 28 | /// This object contains result data of the traversal and should 29 | /// have been initialized by the caller. 30 | /// This method accepts the current node and the result object 31 | /// as aparameter to the required processing on each node. 32 | /// Optional generic method accepts the cuurent node as parameter 33 | /// and implements a progress indicator. 34 | /// Optional generic method accepts the current node 35 | /// and result object as parameter to implement exception handling 36 | /// for browsing of children. 37 | public TRESULT Traverse(T root 38 | , Func> children 39 | , TRESULT ret 40 | , Func process 41 | , Action progress = null 42 | , Func exception = null 43 | ) 44 | { 45 | Queue> queue = new Queue>(); 46 | 47 | if (root != null) 48 | queue.Enqueue(new Tuple(0, root)); 49 | 50 | while (queue.Count() > 0) 51 | { 52 | var queueItem = queue.Dequeue(); 53 | int iLevel = queueItem.Item1; 54 | T current = queueItem.Item2; 55 | 56 | if (progress != null) 57 | progress(current); 58 | 59 | ret = process(ret, current); // Process the node 60 | 61 | try 62 | { 63 | foreach (var item in children(current)) 64 | queue.Enqueue(new Tuple(iLevel + 1, item)); 65 | } 66 | catch (Exception e) 67 | { 68 | if (exception != null) 69 | ret = exception(ret, e, current); // print a simple progress indicator 70 | } 71 | } 72 | 73 | return ret; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /source/Shared/BreadthFirst/TraverseLevelOrder.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLib.BreadthFirst 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using TreeLib.Models; 7 | 8 | /// 9 | /// http://urosv.blogspot.de/2011/04/iterative-binary-tree-traversal.html 10 | /// C/C++ Blog Post by: Uros Vidojevic 11 | /// 12 | /// Levelorder traversal implementation is very similar 13 | /// to the preorder implementation, with the most significant difference 14 | /// that now the is used instead of a 15 | /// . 16 | /// 17 | public partial class Traverse 18 | { 19 | /// 20 | /// Provides a Generic implementaion for a DepthFirst (Pre-Order) 21 | /// Traversal algorithm, which can be used to traverse a n-ary tree 22 | /// via foreach(var item in collection){ ... } 23 | /// 24 | /// This method expects a tree with one root node 25 | /// (e.g. Explorer in Windows). 26 | /// 27 | /// Levelorder traversal implementation is very similar 28 | /// to the preorder implementation, with the most significant difference 29 | /// that now the is used instead of a 30 | /// . 31 | /// 32 | /// 33 | /// 34 | /// 35 | /// 36 | public static IEnumerable> LevelOrder( 37 | T root 38 | , Func> children) 39 | { 40 | if (children == null) 41 | throw new ArgumentNullException(nameof(children)); 42 | 43 | return LevelOrderIterator(root, children); 44 | } 45 | 46 | private static IEnumerable> LevelOrderIterator( 47 | T root 48 | , Func> children) 49 | { 50 | int iLevel = 0; 51 | var current = new Tuple(iLevel++, root); 52 | Queue>> queue = new Queue>>(); 53 | 54 | if (current != null) 55 | queue.Enqueue(new Tuple>(current.Item1, new List{ current.Item2}.GetEnumerator())); 56 | 57 | try 58 | { 59 | while (queue.Count > 0) 60 | { 61 | var queueIt = queue.Dequeue(); 62 | while (queueIt.Item2.MoveNext()) 63 | { 64 | var queueItem = queueIt.Item2.Current; 65 | yield return new LevelOrderCursor(queueIt.Item1, queueItem); 66 | 67 | if (children(queueItem).FirstOrDefault() != null) 68 | queue.Enqueue(new Tuple>(iLevel, children(queueItem).GetEnumerator())); 69 | } 70 | 71 | iLevel++; 72 | continue; 73 | } 74 | } 75 | finally 76 | { 77 | // guarantee that everything is cleaned up even 78 | // if we don't enumerate all the way through 79 | while (queue.Count > 0) 80 | { 81 | queue.Dequeue().Item2.Dispose(); 82 | } 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /source/Shared/BreadthFirst/TraverseLevelOrderEnumerableRoot.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLib.BreadthFirst 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using TreeLib.Models; 7 | 8 | /// 9 | /// Code is based on: 10 | /// http://urosv.blogspot.de/2011/04/iterative-binary-tree-traversal.html 11 | /// C/C++ Blog Post by: Uros Vidojevic (2010) 12 | /// 13 | /// 14 | public partial class Traverse 15 | { 16 | /// 17 | /// Provides a Generic implementaion for a DepthFirst (Pre-Order) 18 | /// Traversal algorithm, which can be used to traverse a n-ary tree 19 | /// via foreach(var item in collection){ ... } 20 | /// 21 | /// This method expects a tree with more than one root node 22 | /// (e.g. Database Explorer in VS when connecting to more than one database). 23 | /// 24 | /// Levelorder traversal implementation is very similar 25 | /// to the preorder implementation, with the most significant difference 26 | /// that now the is used instead of a 27 | /// . 28 | /// 29 | /// 30 | /// 31 | /// 32 | /// 33 | public static IEnumerable> LevelOrder( 34 | IEnumerable root 35 | , Func> children) 36 | { 37 | if (children == null) 38 | throw new ArgumentNullException(nameof(children)); 39 | 40 | return LevelOrderIterator(root, children); 41 | } 42 | 43 | private static IEnumerable> LevelOrderIterator( 44 | IEnumerable root 45 | , Func> children) 46 | { 47 | int iLevel = 0; 48 | var current = root; 49 | Queue>> queue = new Queue>>(); 50 | 51 | if (current != null) 52 | queue.Enqueue(new Tuple>(iLevel++, root.GetEnumerator())); 53 | 54 | try 55 | { 56 | while (queue.Count > 0) 57 | { 58 | var queueIt = queue.Dequeue(); 59 | while (queueIt.Item2.MoveNext()) 60 | { 61 | var queueItem = queueIt.Item2.Current; 62 | yield return new LevelOrderCursor(queueIt.Item1, queueItem); 63 | 64 | if (children(queueItem).FirstOrDefault() != null) 65 | queue.Enqueue(new Tuple>(iLevel, children(queueItem).GetEnumerator())); 66 | } 67 | 68 | iLevel++; 69 | continue; 70 | } 71 | } 72 | finally 73 | { 74 | // guarantee that everything is cleaned up even 75 | // if we don't enumerate all the way through 76 | while (queue.Count > 0) 77 | { 78 | queue.Dequeue().Item2.Dispose(); 79 | } 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /source/Shared/Depthfirst/PostOrder.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLib.Depthfirst 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | /// 8 | /// Implements a Generic class that can traverse a tree with tree nodes of type 9 | /// and supports invoking calls on each node via 10 | /// Generic method in the Traversal method. 11 | /// 12 | /// 13 | /// 14 | public class PostOrder 15 | { 16 | /// 17 | /// This code shows the first development version of the PostOrder 18 | /// traversal algorithm as published by Dave Remy in his 2010 RemLog blog at: 19 | /// https://blogs.msdn.microsoft.com/daveremy/2010/03/16/non-recursive-post-order-depth-first-traversal-in-c/ 20 | /// 21 | /// 22 | /// This object points at the root of the tree structure. 23 | /// This Generic method implements a way of enumerating all 24 | /// childrens for the root or current node in the traversal. 25 | /// This object contains result data of the traversal and should 26 | /// have been initialized by the caller. 27 | /// This method accepts the current node and the result object 28 | /// as aparameter to the required processing on each node. 29 | /// Optional generic method accepts the cuurent node as parameter 30 | /// and implements a progress indicator. 31 | /// Optional generic method accepts the current node 32 | /// and result object as parameter to implement exception handling 33 | /// for browsing of children. 34 | public TRESULT Traverse(T root 35 | , Func> children 36 | , TRESULT ret 37 | , Func process 38 | , Action progress = null 39 | , Func exception = null 40 | ) 41 | { 42 | var toVisit = new Stack(); 43 | var visitedAncestors = new Stack(); 44 | 45 | toVisit.Push(root); 46 | while (toVisit.Count > 0) 47 | { 48 | var current = toVisit.Peek(); 49 | int iChildrenCount = 0; 50 | 51 | try 52 | { 53 | iChildrenCount = children(current).Count(); 54 | } 55 | catch (Exception e) 56 | { 57 | if (exception != null) 58 | ret = exception(ret, e, current); // exception handling 59 | } 60 | 61 | 62 | if (iChildrenCount > 0) 63 | { 64 | if (current.Equals(PeekOrDefault(visitedAncestors)) == false) 65 | { 66 | visitedAncestors.Push(current); 67 | 68 | try 69 | { 70 | PushReverse(toVisit, children(current).ToArray()); 71 | } 72 | catch (Exception e) 73 | { 74 | if (exception != null) 75 | ret = exception(ret, e, current); // exception handling 76 | } 77 | continue; 78 | } 79 | 80 | visitedAncestors.Pop(); 81 | } 82 | 83 | if (progress != null) 84 | progress(current); 85 | 86 | ret = process(ret, current); // Process the node 87 | 88 | toVisit.Pop(); 89 | } 90 | 91 | return ret; 92 | } 93 | 94 | /// 95 | /// Return the top element of stack or null if the Stack is empty. 96 | /// 97 | /// 98 | /// 99 | private T PeekOrDefault(Stack s) 100 | { 101 | return s.Count == 0 ? default(T) : s.Peek(); 102 | } 103 | 104 | /// 105 | /// Push all children of a given node in reverse order into the 106 | /// . 107 | /// 108 | /// Use this to traverse the tree from left to right. 109 | /// 110 | /// 111 | /// 112 | private void PushReverse(Stack s, T[] list) 113 | { 114 | foreach (var l in list.Reverse()) 115 | s.Push(l); 116 | } 117 | } 118 | } 119 | 120 | -------------------------------------------------------------------------------- /source/Shared/Depthfirst/PreOrder.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLib.Depthfirst 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | /// 8 | /// Implements a Generic class that can traverse a tree with tree nodes of type 9 | /// and supports invoking calls on each node via 10 | /// Generic method in the Traversal method. 11 | /// 12 | /// 13 | /// 14 | public class PreOrder 15 | { 16 | /// 17 | /// This code shows the first development version of the PreOrder 18 | /// traversal algorithm as published by Dave Remy in his 2010 RemLog blog at: 19 | /// https://blogs.msdn.microsoft.com/daveremy/2010/03/16/non-recursive-post-order-depth-first-traversal-in-c/ 20 | /// 21 | /// 22 | /// This object points at the root of the tree structure. 23 | /// This Generic method implements a way of enumerating all 24 | /// childrens for the root or current node in the traversal. 25 | /// This object contains result data of the traversal and should 26 | /// have been initialized by the caller. 27 | /// This method accepts the current node and the result object 28 | /// as aparameter to the required processing on each node. 29 | /// Optional generic method accepts the cuurent node as parameter 30 | /// and implements a progress indicator. 31 | /// Optional generic method accepts the current node 32 | /// and result object as parameter to implement exception handling 33 | /// for browsing of children. 34 | public TRESULT Traverse(T root 35 | , Func> children 36 | , TRESULT ret 37 | , Func process 38 | , Action progress = null 39 | , Func exception = null 40 | ) 41 | { 42 | var stack = new Stack(); 43 | stack.Push(root); 44 | 45 | while (stack.Count > 0) 46 | { 47 | var current = stack.Pop(); 48 | 49 | if (progress != null) 50 | progress(current); 51 | 52 | ret = process(ret, current); // Process the node 53 | 54 | try 55 | { 56 | var list = children(current).ToArray(); 57 | 58 | for (int i = list.Count() - 1; i >= 0; i--) 59 | { 60 | stack.Push(list[i]); 61 | } 62 | } 63 | catch (Exception e) 64 | { 65 | if (exception != null) 66 | ret = exception(ret, e, current); // exception handling 67 | } 68 | } 69 | 70 | return ret; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /source/Shared/Depthfirst/TraversePostOrder.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLib.Depthfirst 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | /// 7 | /// Developed out of the combined posts 8 | /// 1) Published by Dave Remy in his 2010 RemLog blog at: 9 | /// https://blogs.msdn.microsoft.com/daveremy/2010/03/16/non-recursive-post-order-depth-first-traversal-in-c/ 10 | /// 11 | /// 2) With the "Generic Tree and Linked List Traversal in C#" post by Mike Adelson 12 | /// http://www.codeducky.org/easy-tree-and-linked-list-traversal-in-c/ 13 | /// 14 | /// http://www.codeducky.org/easy-tree-and-linked-list-traversal-in-c/ 15 | /// https://github.com/madelson/MedallionUtilities/blob/master/MedallionCollections/Traverse.cs 16 | /// by Mike Adelson 17 | /// 18 | public partial class Traverse 19 | { 20 | /// 21 | /// Provides a Generic implementaion for a DepthFirst (Pre-Order) 22 | /// Traversal algorithm, which can be used to traverse a n-ary tree 23 | /// via foreach(var item in collection){ ... } 24 | /// 25 | /// This method expects a tree with one root node 26 | /// (e.g. Explorer in Windows). 27 | /// 28 | /// 29 | /// 30 | /// 31 | /// 32 | public static IEnumerable PostOrder( 33 | T root 34 | , Func> children) 35 | { 36 | if (children == null) 37 | throw new ArgumentNullException(nameof(children)); 38 | 39 | return PostOrderIterator(root, children); 40 | } 41 | 42 | /// 43 | /// Implements a state keeping class that can be used in a traversal algorithm 44 | /// to decide whether the tree should be traversed: 45 | /// - down (towards children of a node) 46 | /// - the node itself should be visited or whether the 47 | /// - parents of the node should be visited. 48 | /// 49 | /// 50 | class VisitElement : IDisposable 51 | { 52 | #region fields 53 | private T _Element; 54 | private IEnumerator _EnumerateChildren; 55 | private bool _disposed; 56 | #endregion fields 57 | 58 | #region ctors 59 | /// 60 | /// Class constructor 61 | /// 62 | /// 63 | /// 64 | public VisitElement(T element, IEnumerator enumerateChildren) 65 | : this() 66 | { 67 | _Element = element; 68 | _EnumerateChildren = enumerateChildren; 69 | } 70 | 71 | /// 72 | /// Hidden class constructor 73 | /// 74 | protected VisitElement() 75 | { 76 | } 77 | #endregion ctors 78 | 79 | #region properties 80 | /// 81 | /// Gets whether the children of this element have already been visited or not. 82 | /// 83 | public bool ChildrenVisited { get; protected set; } 84 | 85 | /// 86 | /// Gets whether this element has already been visited or not. 87 | /// 88 | public bool ThisElementVisited { get; protected set; } 89 | 90 | /// 91 | /// Gets the Element for this node or null if this is the root. 92 | /// 93 | public T Element { get { return _Element; } } 94 | #endregion properties 95 | 96 | #region methods 97 | /// 98 | /// Gets the next available child or null (if all children have been enumerated). 99 | /// 100 | /// 101 | public T GetNextChild() 102 | { 103 | if (_EnumerateChildren != null) 104 | { 105 | if (_EnumerateChildren.MoveNext()) 106 | return _EnumerateChildren.Current; 107 | } 108 | 109 | ChildrenVisited = true; 110 | return default(T); 111 | } 112 | 113 | /// 114 | /// Marks this element as having been visited. 115 | /// 116 | public void SetThisElementVisited() 117 | { 118 | ThisElementVisited = true; 119 | } 120 | 121 | #region Disposable Interfaces 122 | /// 123 | /// Standard dispose method of the interface. 124 | /// 125 | public void Dispose() 126 | { 127 | Dispose(true); 128 | } 129 | 130 | /// 131 | /// Source: http://www.codeproject.com/Articles/15360/Implementing-IDisposable-and-the-Dispose-Pattern-P 132 | /// 133 | /// 134 | protected void Dispose(bool disposing) 135 | { 136 | if (_disposed == false) 137 | { 138 | if (disposing == true) 139 | { 140 | // Dispose of the curently displayed content if it is disposable 141 | if (_EnumerateChildren != null) 142 | { 143 | _EnumerateChildren.Dispose(); 144 | _EnumerateChildren = null; 145 | } 146 | } 147 | 148 | // There are no unmanaged resources to release, but 149 | // if we add them, they need to be released here. 150 | } 151 | 152 | _disposed = true; 153 | 154 | //// If it is available, make the call to the 155 | //// base class's Dispose(Boolean) method 156 | ////base.Dispose(disposing); 157 | } 158 | #endregion Disposable Interfaces 159 | #endregion methods 160 | } 161 | 162 | private static IEnumerable PostOrderIterator( 163 | T root 164 | , Func> children) 165 | { 166 | var toVisit = new Stack>(); 167 | 168 | try 169 | { 170 | var it = new List { root }.GetEnumerator(); 171 | var element = new VisitElement(default(T), it); 172 | toVisit.Push(element); 173 | 174 | while (toVisit.Count > 0) 175 | { 176 | var node = toVisit.Peek(); 177 | 178 | if (node.ChildrenVisited == false) 179 | { 180 | var child = node.GetNextChild(); 181 | if (child == null) 182 | { 183 | // Is this a non-root element? 184 | if (node.Element != null) 185 | { 186 | node.SetThisElementVisited(); 187 | yield return node.Element; 188 | } 189 | else 190 | yield break; 191 | 192 | continue; 193 | } 194 | else 195 | { 196 | // Put this child on the stack and continue to dive down 197 | element = new VisitElement(child, children(child).GetEnumerator()); 198 | toVisit.Push(element); 199 | continue; 200 | } 201 | } 202 | else 203 | { 204 | if (node.ThisElementVisited == false) 205 | { 206 | // Is this a non-root element? 207 | if (node.Element != null) 208 | { 209 | node.SetThisElementVisited(); 210 | yield return node.Element; 211 | } 212 | else 213 | yield break; 214 | 215 | continue; 216 | } 217 | else // This node and its children have been visited 218 | toVisit.Pop(); 219 | } 220 | } 221 | } 222 | finally 223 | { 224 | // guarantee that everything is cleaned up even 225 | // if we don't enumerate all the way through 226 | while (toVisit.Count > 0) 227 | { 228 | toVisit.Pop().Dispose(); 229 | } 230 | } 231 | } 232 | 233 | /// 234 | /// Return the top element of stack or null if the Stack is empty. 235 | /// 236 | /// 237 | /// 238 | private static T PeekOrDefault1(Stack s) 239 | { 240 | return s.Count == 0 ? default(T) : s.Peek(); 241 | } 242 | 243 | /// 244 | /// Push all children of a given node in givrn order into the 245 | /// . 246 | /// 247 | /// Use this to traverse the tree from right to left. 248 | /// 249 | /// 250 | /// 251 | private static void PushNonReverse(Stack> s, IEnumerable list) 252 | { 253 | s.Push(list.GetEnumerator()); 254 | } 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /source/Shared/Depthfirst/TraversePostOrderEnumerableRoot.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLib.Depthfirst 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | /// 8 | /// Developed out of the combined posts 9 | /// 1) Published by Dave Remy in his 2010 RemLog blog at: 10 | /// https://blogs.msdn.microsoft.com/daveremy/2010/03/16/non-recursive-post-order-depth-first-traversal-in-c/ 11 | /// 12 | /// 2) With the "Generic Tree and Linked List Traversal in C#" post by Mike Adelson 13 | /// http://www.codeducky.org/easy-tree-and-linked-list-traversal-in-c/ 14 | /// 15 | /// http://www.codeducky.org/easy-tree-and-linked-list-traversal-in-c/ 16 | /// https://github.com/madelson/MedallionUtilities/blob/master/MedallionCollections/Traverse.cs 17 | /// by Mike Adelson 18 | /// 19 | public partial class Traverse 20 | { 21 | /// 22 | /// Provides a Generic implementaion for a Post-Order (DepthFirst) 23 | /// Traversal algorithm, which can be used to traverse a n-ary tree 24 | /// via foreach(var item in collection){ ... } 25 | /// 26 | /// This method expects a tree with more than one root node 27 | /// (e.g. Database Explorer in VS when connecting to more than one database). 28 | /// 29 | /// 30 | /// 31 | /// 32 | /// 33 | public static IEnumerable PostOrder( 34 | IEnumerable root 35 | , Func> children) 36 | { 37 | if (children == null) 38 | throw new ArgumentNullException(nameof(children)); 39 | 40 | return PostOrderIterator(root, children); 41 | } 42 | 43 | private static IEnumerable PostOrderIterator( 44 | IEnumerable root 45 | , Func> children) 46 | { 47 | var toVisit = new Stack>(); 48 | var visitedAncestors = new Stack(); 49 | 50 | try 51 | { 52 | var it = root.GetEnumerator(); 53 | toVisit.Push(it); 54 | 55 | while (toVisit.Count > 0) 56 | { 57 | T current = default(T); 58 | var node = toVisit.Peek(); 59 | if (node.MoveNext()) 60 | { 61 | current = node.Current; 62 | } 63 | else 64 | { 65 | // otherwise, cleanup the empty enumerator and... 66 | node.Dispose(); 67 | 68 | // ...search up the stack for an enumerator with elements left 69 | while (true) 70 | { 71 | if (toVisit.Count == 0) 72 | { 73 | // we didn't find one, so we're all done 74 | yield break; 75 | } 76 | 77 | // consider the next enumerator on the stack 78 | var topEnumerator = toVisit.Peek(); 79 | if (topEnumerator.MoveNext()) 80 | { 81 | // if it has an element, use it 82 | current = topEnumerator.Current; 83 | //break; 84 | } 85 | else 86 | { 87 | // otherwise discard it 88 | toVisit.Pop().Dispose(); 89 | 90 | if (visitedAncestors.Count() > 0) 91 | { 92 | current = visitedAncestors.Pop(); 93 | yield return current; 94 | } 95 | else 96 | yield break; // Done Done :-) 97 | } 98 | } 99 | } 100 | 101 | if (children(current).FirstOrDefault() != null) 102 | { 103 | if (current.Equals(PeekOrDefault1(visitedAncestors)) == false) 104 | { 105 | visitedAncestors.Push(current); 106 | PushNonReverse(toVisit, children(current)); 107 | continue; 108 | } 109 | 110 | visitedAncestors.Pop(); 111 | } 112 | 113 | //System.Console.WriteLine(node.GetStackPath()); // Process the node 114 | yield return current; 115 | 116 | //toVisit.Pop(); 117 | node = toVisit.Peek(); 118 | if (node.MoveNext()) 119 | { 120 | current = node.Current; 121 | yield return current; 122 | } 123 | else 124 | { 125 | node = toVisit.Pop(); 126 | // otherwise, cleanup the empty enumerator and... 127 | node.Dispose(); 128 | 129 | // ...search up the stack for an enumerator with elements left 130 | while (true) 131 | { 132 | if (toVisit.Count == 0) 133 | { 134 | // we didn't find one, so we're all done 135 | yield break; 136 | } 137 | 138 | // consider the next enumerator on the stack 139 | var topEnumerator = toVisit.Peek(); 140 | 141 | current = topEnumerator.Current; 142 | visitedAncestors.Pop(); 143 | yield return current; 144 | 145 | if (topEnumerator.MoveNext()) 146 | { 147 | // if it has an element, use it 148 | current = topEnumerator.Current; 149 | 150 | if (children(current).FirstOrDefault() != null) 151 | { 152 | if (current.Equals(PeekOrDefault1(visitedAncestors)) == false) 153 | { 154 | visitedAncestors.Push(current); 155 | PushNonReverse(toVisit, children(current)); 156 | break; 157 | } 158 | } 159 | 160 | yield return current; 161 | } 162 | else 163 | { 164 | // otherwise discard it 165 | toVisit.Pop().Dispose(); 166 | } 167 | } 168 | } 169 | } 170 | } 171 | finally 172 | { 173 | // guarantee that everything is cleaned up even 174 | // if we don't enumerate all the way through 175 | while (toVisit.Count > 0) 176 | { 177 | toVisit.Pop().Dispose(); 178 | } 179 | } 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /source/Shared/Depthfirst/TraversePreorder.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLib.Depthfirst 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | /// 7 | /// Code is based on this source: 8 | /// http://www.codeducky.org/easy-tree-and-linked-list-traversal-in-c/ 9 | /// https://github.com/madelson/MedallionUtilities/blob/master/MedallionCollections/Traverse.cs 10 | /// by Mike Adelson 11 | /// 12 | public partial class Traverse 13 | { 14 | /// 15 | /// Provides a Generic implementaion for a Preorder (DepthFirst) tree 16 | /// traversal algorithm, which can be used to traverse a n-ary tree 17 | /// via foreach(var item in collection){ ... } 18 | /// 19 | /// This method expects a tree with one root node 20 | /// (e.g. Explorer in Windows). 21 | /// 22 | /// 23 | /// 24 | /// 25 | /// 26 | public static IEnumerable Preorder( 27 | T root 28 | , Func> children) 29 | { 30 | if (children == null) 31 | throw new ArgumentNullException(nameof(children)); 32 | 33 | return PreorderIterator(root, children); 34 | } 35 | 36 | private static IEnumerable PreorderIterator( 37 | T root 38 | , Func> children) 39 | { 40 | var current = root; 41 | var stack = new Stack>(); 42 | 43 | try 44 | { 45 | while (true) 46 | { 47 | yield return current; 48 | 49 | var childrenEnumerator = children(current).GetEnumerator(); 50 | if (childrenEnumerator.MoveNext()) 51 | { 52 | // if we have children, the first child is our next current 53 | // and push the new enumerator 54 | current = childrenEnumerator.Current; 55 | stack.Push(childrenEnumerator); 56 | } 57 | else 58 | { 59 | // otherwise, cleanup the empty enumerator and... 60 | childrenEnumerator.Dispose(); 61 | 62 | // ...search up the stack for an enumerator with elements left 63 | while (true) 64 | { 65 | if (stack.Count == 0) 66 | { 67 | // we didn't find one, so we're all done 68 | yield break; 69 | } 70 | 71 | // consider the next enumerator on the stack 72 | var topEnumerator = stack.Peek(); 73 | if (topEnumerator.MoveNext()) 74 | { 75 | // if it has an element, use it 76 | current = topEnumerator.Current; 77 | break; 78 | } 79 | else 80 | { 81 | // otherwise discard it 82 | stack.Pop().Dispose(); 83 | } 84 | } 85 | } 86 | } 87 | } 88 | finally 89 | { 90 | // guarantee that everything is cleaned up even 91 | // if we don't enumerate all the way through 92 | while (stack.Count > 0) 93 | { 94 | stack.Pop().Dispose(); 95 | } 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /source/Shared/Depthfirst/TraversePreorderEnumerableRoot.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLib.Depthfirst 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | /// 7 | /// Code is based on this source: 8 | /// http://www.codeducky.org/easy-tree-and-linked-list-traversal-in-c/ 9 | /// https://github.com/madelson/MedallionUtilities/blob/master/MedallionCollections/Traverse.cs 10 | /// by Mike Adelson 11 | /// 12 | public partial class Traverse 13 | { 14 | /// 15 | /// Provides a Generic implementaion for a Preorder (DepthFirst) tree 16 | /// traversal algorithm, which can be used to traverse a n-ary tree 17 | /// via foreach(var item in collection){ ... } 18 | /// 19 | /// This method expects a tree with multiple root nodes 20 | /// (e.g. Explorer in Windows). 21 | /// 22 | /// 23 | /// 24 | /// 25 | /// 26 | public static IEnumerable Preorder( 27 | IEnumerator root 28 | , Func> children) 29 | { 30 | if (children == null) 31 | throw new ArgumentNullException(nameof(children)); 32 | 33 | return PreorderIterator(root, children); 34 | } 35 | 36 | private static IEnumerable PreorderIterator( 37 | IEnumerator root 38 | , Func> children) 39 | { 40 | T current = default(T); 41 | var stack = new Stack>(); 42 | stack.Push(root); 43 | 44 | if (root.MoveNext()) 45 | current = root.Current; 46 | else 47 | yield break; // Got empty IEnumerable here 48 | 49 | try 50 | { 51 | while (true) 52 | { 53 | yield return current; 54 | 55 | var childrenEnumerator = children(current).GetEnumerator(); 56 | if (childrenEnumerator.MoveNext()) 57 | { 58 | // if we have children, the first child is our next current 59 | // and push the new enumerator 60 | current = childrenEnumerator.Current; 61 | stack.Push(childrenEnumerator); 62 | } 63 | else 64 | { 65 | // otherwise, cleanup the empty enumerator and... 66 | childrenEnumerator.Dispose(); 67 | 68 | // ...search up the stack for an enumerator with elements left 69 | while (true) 70 | { 71 | if (stack.Count == 0) 72 | { 73 | // we didn't find one, so we're all done 74 | yield break; 75 | } 76 | 77 | // consider the next enumerator on the stack 78 | var topEnumerator = stack.Peek(); 79 | if (topEnumerator.MoveNext()) 80 | { 81 | // if it has an element, use it 82 | current = topEnumerator.Current; 83 | break; 84 | } 85 | else 86 | { 87 | // otherwise discard it 88 | stack.Pop().Dispose(); 89 | } 90 | } 91 | } 92 | } 93 | } 94 | finally 95 | { 96 | // guarantee that everything is cleaned up even 97 | // if we don't enumerate all the way through 98 | while (stack.Count > 0) 99 | { 100 | stack.Pop().Dispose(); 101 | } 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /source/Shared/Models/LevelOrderCursor.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLib.Models 2 | { 3 | /// 4 | /// This class implements a simple traversal cursor to indicate 5 | /// the next element being enumerated and its level. 6 | /// (see enumeration function in 7 | /// 8 | /// 9 | public class LevelOrderCursor 10 | { 11 | /// 12 | /// Class constructor 13 | /// 14 | /// 15 | /// 16 | public LevelOrderCursor(int level, T node) 17 | : this() 18 | { 19 | Level = level; 20 | Node = node; 21 | } 22 | 23 | /// 24 | /// Hidden class constructor. 25 | /// 26 | protected LevelOrderCursor() 27 | { 28 | } 29 | 30 | /// 31 | /// The level indicates the zero based level at which the 32 | /// corresponding is contained within 33 | /// the tree. 34 | /// 35 | public int Level { get; private set; } 36 | 37 | /// 38 | /// Indicates the tree node that is visited when this class 39 | /// is returned from an IEnumerable>T> function. 40 | /// 41 | public T Node { get; private set; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /source/Shared/Shared.projitems: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | a23bd0cf-4f74-42ba-b89a-141c0d75d3a1 7 | 8 | 9 | Shared 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /source/Shared/Shared.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | a23bd0cf-4f74-42ba-b89a-141c0d75d3a1 5 | 14.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /source/TreeLib/Readme.txt: -------------------------------------------------------------------------------- 1 | 2 | Overview 3 | -------- 4 | 5 | Handling tree structured data in C#/.Net often requires us to traverse (visit) 6 | each node (and their children) in a certain order. 7 | 8 | A store (serialize) and restore (deserialize) algorithm usually requires a 9 | LevelOrder or PreOrder traversal from the root node(s) down to the bottom, 10 | in which, each node is visited exactly once. 11 | 12 | Other algorithms, that require us to compute a value from the leaf up to the root 13 | may require a PostOrder traversal. This solution contains a short overview on this 14 | topic (see below) and Generic algorithms that can be used on any tree (be it binary 15 | or n-ary - each node can have n children with any n > 0). 16 | 17 | Classification 18 | -------------- 19 | The world of Binary Tree traversal algorithms can be split into: 20 | 21 | 1 Breadth First 22 | +-> Level Order 23 | 24 | 2 Depth First 25 | +-> PreOrder 26 | +-> InOrder 27 | +-> Postorder 28 | 29 | Watch this video to understand what is what (and why these names make some sense): 30 | Binary tree traversal: Preorder, Inorder, Postorder 31 | https://www.youtube.com/watch?v=gm8DUJJhmY4 32 | Author: mycodeschool 33 | -------------------------------------------------------------------------------- /source/TreeLib/TreeLib.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | netstandard2.0 7 | Dirkster.TreeLib 8 | 1.0.0 9 | Dirk Bahle 10 | https://github.com/Dirkster99/TreeLib 11 | This library contains Generic algorithm implementations for tree traversals, such as, LevelOrder, PreOrder, and PostOrder. Each algorithm is available with a visitor pattern that returns IEnumerable<T>, which means these implementations should scale very well for traversing large trees (with a lot of child nodes and/or depth). 12 | false 13 | Second release with Fixed PostOrder Algorithm that returns IEnumerable<T>. 14 | Copyright 2017-2019 (c) Dirk Bahle. All rights reserved. 15 | generic tree traversal method LevelOrder PreOrder PostOrder 16 | 1.2.0.0 17 | 1.2.0.0 18 | 1.2.0 19 | 20 | 21 | 22 | bin\Debug\netstandard1.4\TreeLib.xml 23 | 24 | 25 | 26 | bin\Release\netstandard1.4\TreeLib.xml 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /source/TreeLibDemo.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.27004.2009 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TreeLibDemo", "TreeLibDemo\TreeLibDemo.csproj", "{45414A0F-D85D-435F-95E8-E7FD6BA2716F}" 6 | EndProject 7 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TreeLib", "TreeLib\TreeLib.csproj", "{7768B30A-FD1C-4994-97DD-C06F959FBE21}" 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TreeLibNugetDemo", "TreeLibNugetDemo\TreeLibNugetDemo.csproj", "{607B4973-E3DB-4071-83C6-DDF301D39A32}" 10 | EndProject 11 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Shared", "Shared\Shared.shproj", "{A23BD0CF-4F74-42BA-B89A-141C0D75D3A1}" 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TreeLibNet", "TreeLibNet\TreeLibNet.csproj", "{882E7E61-8000-4396-9067-0A5B25258BD4}" 14 | EndProject 15 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libs", "Libs", "{258E5C47-C38C-4B61-ABEE-A83240383503}" 16 | EndProject 17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TreeLibNugetUnitTests", "TreeLibNugetUnitTests\TreeLibNugetUnitTests.csproj", "{7ECB4D90-C421-4500-817E-322281D5061F}" 18 | EndProject 19 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TreeLibDemoLib", "TreeLibDemoLib\TreeLibDemoLib.csproj", "{A2328C9B-04EC-4B79-A6F3-5A0B3FD7D3AC}" 20 | EndProject 21 | Global 22 | GlobalSection(SharedMSBuildProjectFiles) = preSolution 23 | Shared\Shared.projitems*{882e7e61-8000-4396-9067-0a5b25258bd4}*SharedItemsImports = 4 24 | Shared\Shared.projitems*{a23bd0cf-4f74-42ba-b89a-141c0d75d3a1}*SharedItemsImports = 13 25 | EndGlobalSection 26 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 27 | Debug|Any CPU = Debug|Any CPU 28 | Release|Any CPU = Release|Any CPU 29 | EndGlobalSection 30 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 31 | {45414A0F-D85D-435F-95E8-E7FD6BA2716F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {45414A0F-D85D-435F-95E8-E7FD6BA2716F}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {45414A0F-D85D-435F-95E8-E7FD6BA2716F}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {45414A0F-D85D-435F-95E8-E7FD6BA2716F}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {7768B30A-FD1C-4994-97DD-C06F959FBE21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {7768B30A-FD1C-4994-97DD-C06F959FBE21}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {7768B30A-FD1C-4994-97DD-C06F959FBE21}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {7768B30A-FD1C-4994-97DD-C06F959FBE21}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {607B4973-E3DB-4071-83C6-DDF301D39A32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 40 | {607B4973-E3DB-4071-83C6-DDF301D39A32}.Debug|Any CPU.Build.0 = Debug|Any CPU 41 | {607B4973-E3DB-4071-83C6-DDF301D39A32}.Release|Any CPU.ActiveCfg = Release|Any CPU 42 | {607B4973-E3DB-4071-83C6-DDF301D39A32}.Release|Any CPU.Build.0 = Release|Any CPU 43 | {882E7E61-8000-4396-9067-0A5B25258BD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 44 | {882E7E61-8000-4396-9067-0A5B25258BD4}.Debug|Any CPU.Build.0 = Debug|Any CPU 45 | {882E7E61-8000-4396-9067-0A5B25258BD4}.Release|Any CPU.ActiveCfg = Release|Any CPU 46 | {882E7E61-8000-4396-9067-0A5B25258BD4}.Release|Any CPU.Build.0 = Release|Any CPU 47 | {7ECB4D90-C421-4500-817E-322281D5061F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 48 | {7ECB4D90-C421-4500-817E-322281D5061F}.Debug|Any CPU.Build.0 = Debug|Any CPU 49 | {7ECB4D90-C421-4500-817E-322281D5061F}.Release|Any CPU.ActiveCfg = Release|Any CPU 50 | {7ECB4D90-C421-4500-817E-322281D5061F}.Release|Any CPU.Build.0 = Release|Any CPU 51 | {A2328C9B-04EC-4B79-A6F3-5A0B3FD7D3AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 52 | {A2328C9B-04EC-4B79-A6F3-5A0B3FD7D3AC}.Debug|Any CPU.Build.0 = Debug|Any CPU 53 | {A2328C9B-04EC-4B79-A6F3-5A0B3FD7D3AC}.Release|Any CPU.ActiveCfg = Release|Any CPU 54 | {A2328C9B-04EC-4B79-A6F3-5A0B3FD7D3AC}.Release|Any CPU.Build.0 = Release|Any CPU 55 | EndGlobalSection 56 | GlobalSection(SolutionProperties) = preSolution 57 | HideSolutionNode = FALSE 58 | EndGlobalSection 59 | GlobalSection(NestedProjects) = preSolution 60 | {7768B30A-FD1C-4994-97DD-C06F959FBE21} = {258E5C47-C38C-4B61-ABEE-A83240383503} 61 | {A23BD0CF-4F74-42BA-B89A-141C0D75D3A1} = {258E5C47-C38C-4B61-ABEE-A83240383503} 62 | {882E7E61-8000-4396-9067-0A5B25258BD4} = {258E5C47-C38C-4B61-ABEE-A83240383503} 63 | EndGlobalSection 64 | GlobalSection(ExtensibilityGlobals) = postSolution 65 | SolutionGuid = {15B61454-7140-4B65-B517-5C3C0E97B683} 66 | EndGlobalSection 67 | EndGlobal 68 | -------------------------------------------------------------------------------- /source/TreeLibDemo/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /source/TreeLibDemo/Program.cs: -------------------------------------------------------------------------------- 1 | namespace TTraversalDemo 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using TreeLibDemoLib; 6 | using TreeLibDemoLib.Development; 7 | 8 | /// 9 | /// This demo application tests different versions of tree traversal algorithms from: 10 | /// 11 | /// Version V1 12 | /// - simple and straight (no generics - just iterative code) 13 | /// 14 | /// Version V2 15 | /// - First devered Generic version without Lazyness. 16 | /// 17 | /// TreeLib.* (Version V3) 18 | /// - Second an Final derived Generic version with Lazyness. 19 | /// 20 | class Program 21 | { 22 | static void Main(string[] args) 23 | { 24 | var root = makeTree(); 25 | 26 | TestLevelOrder(root); 27 | 28 | TestPreOrder(root); 29 | 30 | TestPostOrder(root); 31 | } 32 | 33 | /// 34 | /// Demos all 3 Development versions of the LevelOrder Tree Traversal algorithm 35 | /// in one method. 36 | /// 37 | /// Only the algorithm in the TreeLib library is suppossed to be 38 | /// final - all other version are kept to understand the principal applied to 39 | /// arrive at the Generic patterns in the TreeLib library. 40 | /// 41 | /// 42 | private static void TestLevelOrder(Node root) 43 | { 44 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 45 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX LevelOrder (Breadth-First) 46 | Console.WriteLine("LevelOrderTraversal Tree Traversal V1"); 47 | LevelOrderV1.Traverse(root); 48 | 49 | Console.WriteLine(); 50 | Console.WriteLine("Press any key..."); 51 | Console.ReadKey(); 52 | 53 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX LevelOrder (Breadth-First) 54 | Console.WriteLine("LevelOrderTraversal Tree Traversal V2"); 55 | var lorderitems = LevelOrderV2.Traverse(root, i => i.Children); 56 | 57 | foreach (var item in lorderitems) 58 | { 59 | int iLevel = item.Item1; 60 | Node current = item.Item2; 61 | 62 | Console.WriteLine(string.Format("{0,4} - {1}" 63 | , iLevel, current.GetPath())); 64 | } 65 | 66 | Console.WriteLine(); 67 | Console.WriteLine("Press any key..."); 68 | Console.ReadKey(); 69 | 70 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX LevelOrder (Breadth-First) 71 | Console.WriteLine("LevelOrderTraversal Tree Traversal V3"); 72 | var levorderItems = TreeLib.BreadthFirst.Traverse.LevelOrder(root, i => i.Children); 73 | 74 | foreach (var current in levorderItems) 75 | { 76 | Console.WriteLine(string.Format("{0,4} - {1}", current.Level 77 | , current.Node.GetPath())); 78 | } 79 | 80 | Console.WriteLine(); 81 | Console.WriteLine("Press any key..."); 82 | Console.ReadKey(); 83 | } 84 | 85 | /// 86 | /// Demos all 3 Development versions of the PreOrder Tree Traversal algorithm 87 | /// in one method. 88 | /// 89 | /// Only the algorithm in the TreeLib library is suppossed to be 90 | /// final - all other version are kept to understand the principal applied to 91 | /// arrive at the Generic patterns in the TreeLib library. 92 | /// 93 | /// 94 | private static void TestPreOrder(Node root) 95 | { 96 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 97 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX PreOrder Traversal (Depth-First) 98 | Console.WriteLine("PreOrder (Depth First) Tree Traversal V1"); 99 | PreOrderV1.Traverse(root); 100 | Console.WriteLine(); 101 | Console.WriteLine("Press any key..."); 102 | Console.ReadKey(); 103 | 104 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX PreOrder Traversal (Depth-First) 105 | Console.WriteLine("PreOrder (Depth First) Tree Traversal V2"); 106 | var items = PreOrderV2.Traverse(root, i => i.Children); 107 | foreach (var item in items) 108 | { 109 | Console.WriteLine(item.GetPath()); 110 | } 111 | Console.WriteLine(); 112 | Console.WriteLine("Press any key..."); 113 | Console.ReadKey(); 114 | 115 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX PreOrder Traversal (Depth-First) 116 | Console.WriteLine("PreOrder (Depth First) Tree Traversal V3"); 117 | items = TreeLib.Depthfirst.Traverse.Preorder(root, i => i.Children); 118 | foreach (var item in items) 119 | { 120 | Console.WriteLine(item.GetPath()); 121 | } 122 | Console.WriteLine(); 123 | Console.WriteLine("Press any key..."); 124 | Console.ReadKey(); 125 | 126 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX PreOrder Traversal (Depth-First) 127 | Console.WriteLine("PreOrder (Depth First) Tree Traversal V3 (Multiple Roots Nodes)"); 128 | 129 | var root1 = makeTree(1); 130 | var multipleRoots = new List(){ root, root1}.GetEnumerator(); 131 | 132 | items = TreeLib.Depthfirst.Traverse.Preorder(multipleRoots, i => i.Children); 133 | foreach (var item in items) 134 | { 135 | Console.WriteLine(item.GetPath()); 136 | } 137 | Console.WriteLine(); 138 | Console.WriteLine("Press any key..."); 139 | Console.ReadKey(); 140 | } 141 | 142 | /// 143 | /// Demos all 3 Development versions of the PostOrder Tree Traversal algorithm 144 | /// in one method. 145 | /// 146 | /// Only the algorithm in the TreeLib library is suppossed to be 147 | /// final - all other version are kept to understand the principal applied to 148 | /// arrive at the Generic patterns in the TreeLib library. 149 | /// 150 | /// 151 | private static void TestPostOrder(Node root) 152 | { 153 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 154 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX PostOrder Traversal (Depth-First) 155 | Console.WriteLine("(Depth First) PostOrder Tree Traversal V1"); 156 | PostOrderV1.Traverse(root); 157 | Console.WriteLine(); 158 | Console.WriteLine("Press any key..."); 159 | Console.ReadKey(); 160 | 161 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX PostOrder Traversal (Depth-First) 162 | Console.WriteLine("(Depth First) Post-Order Tree Traversal V2"); 163 | var items = PostOrderV2.Traverse(root, i => i.Children); 164 | 165 | foreach (var item in items) 166 | { 167 | Console.WriteLine(item.GetPath()); 168 | } 169 | Console.WriteLine(); 170 | Console.WriteLine("Press any key..."); 171 | Console.ReadKey(); 172 | 173 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX PostOrder Traversal (Depth-First) 174 | Console.WriteLine("(Depth First) PostOrder Tree Traversal V3"); 175 | items = TreeLib.Depthfirst.Traverse.PostOrder(root, i => i.Children); 176 | 177 | foreach (var item in items) 178 | { 179 | Console.WriteLine(item.GetPath()); 180 | } 181 | Console.WriteLine(); 182 | Console.WriteLine("Press any key..."); 183 | Console.ReadKey(); 184 | } 185 | 186 | /// 187 | /// Returns a simple tree of to work 188 | /// with the demo code in this application. 189 | /// 190 | /// a 191 | /// / | \ 192 | /// b c d 193 | /// /|\ \ \ \ 194 | /// e,f,xyz g h i 195 | /// 196 | /// dfs: efbgchida 197 | /// 198 | /// 199 | private static Node makeTree(int isampleNumber=0) 200 | { 201 | string SampleIndicator = string.Empty; 202 | 203 | if (isampleNumber > 0) 204 | SampleIndicator = isampleNumber.ToString(); 205 | 206 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 207 | 208 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 209 | var c = new Node(a, string.Format("c{0}", SampleIndicator)); 210 | var d = new Node(a, string.Format("d{0}", SampleIndicator)); 211 | a.Children.Add(b); 212 | a.Children.Add(c); 213 | a.Children.Add(d); 214 | 215 | b.Children.Add(new Node(b, string.Format("e{0}", SampleIndicator))); 216 | b.Children.Add(new Node(b, string.Format("f{0}", SampleIndicator))); 217 | b.Children.Add(new Node(b, string.Format("x{0}", SampleIndicator))); 218 | b.Children.Add(new Node(b, string.Format("y{0}", SampleIndicator))); 219 | b.Children.Add(new Node(b, string.Format("z{0}", SampleIndicator))); 220 | 221 | c.Children.Add(new Node(c, string.Format("g{0}", SampleIndicator))); 222 | 223 | d.Children.Add(new Node(d, string.Format("h{0}", SampleIndicator))); 224 | d.Children.Add(new Node(d, string.Format("i{0}", SampleIndicator))); 225 | 226 | return a; 227 | } 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /source/TreeLibDemo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("PostOrderDepthFirstTraversalDemo")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("PostOrderDepthFirstTraversalDemo")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("45414a0f-d85d-435f-95e8-e7fd6ba2716f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.1.0.0")] 36 | [assembly: AssemblyFileVersion("1.1.0.0")] 37 | -------------------------------------------------------------------------------- /source/TreeLibDemo/TreeLibDemo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {45414A0F-D85D-435F-95E8-E7FD6BA2716F} 8 | Exe 9 | TTraversalDemo 10 | TTraversalDemo 11 | v4.5.2 12 | 512 13 | true 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | {a2328c9b-04ec-4b79-a6f3-5a0b3fd7d3ac} 54 | TreeLibDemoLib 55 | 56 | 57 | {882e7e61-8000-4396-9067-0a5b25258bd4} 58 | TreeLibNet 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /source/TreeLibDemoLib/Development/LevelOrderV1.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibDemoLib.Development 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using TreeLibDemoLib; 7 | 8 | static public class LevelOrderV1 9 | { 10 | /// 11 | /// http://urosv.blogspot.de/2011/04/iterative-binary-tree-traversal.html 12 | /// C/C++ Blog Post by: Uros Vidojevic 13 | /// 14 | /// Levelorder traversal implementation is very similar 15 | /// to the preorder implementation, with the most significant difference 16 | /// that the is used instead of a 17 | /// . 18 | /// 19 | /// 20 | public static List Traverse(Node root) 21 | { 22 | List ret = new List(); 23 | Queue> queue = new Queue>(); 24 | 25 | if (root != null) 26 | queue.Enqueue(new Tuple(0, root)); 27 | 28 | while (queue.Count() > 0) 29 | { 30 | var queueItem = queue.Dequeue(); 31 | int iLevel = queueItem.Item1; 32 | Node current = queueItem.Item2; 33 | 34 | ret.Add(current); 35 | Console.WriteLine(string.Format("{0,4} - {1}", iLevel, current.GetPath())); 36 | 37 | foreach (var item in current.Children) 38 | queue.Enqueue(new Tuple(iLevel + 1, item)); 39 | } 40 | 41 | return ret; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /source/TreeLibDemoLib/Development/LevelOrderV2.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibDemoLib.Development 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | public static class LevelOrderV2 8 | { 9 | /// 10 | /// http://urosv.blogspot.de/2011/04/iterative-binary-tree-traversal.html 11 | /// C/C++ Blog Post by: Uros Vidojevic 12 | /// 13 | /// Levelorder traversal implementation is very similar 14 | /// to the preorder implementation, with the most significant difference 15 | /// that now the is used instead of a 16 | /// . 17 | /// 18 | /// 19 | public static IEnumerable> Traverse( 20 | T root 21 | , Func> children) 22 | { 23 | Queue> queue = new Queue>(); 24 | 25 | if (root != null) 26 | queue.Enqueue(new Tuple(0, root)); 27 | 28 | while (queue.Count() > 0) 29 | { 30 | var queueItem = queue.Dequeue(); 31 | int iLevel = queueItem.Item1; 32 | T current = queueItem.Item2; 33 | 34 | yield return new Tuple(iLevel, current) ; 35 | 36 | foreach (var item in children(current)) 37 | queue.Enqueue(new Tuple(iLevel + 1, item)); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /source/TreeLibDemoLib/Development/PostOrderV1.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibDemoLib.Development 2 | { 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | /// 7 | /// This code shows the first development version of the PostOrder 8 | /// traversal algorithm as published by Dave Remy in his 2010 RemLog blog at: 9 | /// https://blogs.msdn.microsoft.com/daveremy/2010/03/16/non-recursive-post-order-depth-first-traversal-in-c/ 10 | /// 11 | public static class PostOrderV1 12 | { 13 | public static List Traverse(Node root) 14 | { 15 | List ret = new List(); 16 | var toVisit = new Stack(); 17 | var visitedAncestors = new Stack(); 18 | 19 | toVisit.Push(root); 20 | while (toVisit.Count > 0) 21 | { 22 | var current = toVisit.Peek(); 23 | if (current.Children.Count > 0) 24 | { 25 | if (PeekOrDefault(visitedAncestors) != current) 26 | { 27 | visitedAncestors.Push(current); 28 | PushReverse(toVisit, current.Children); 29 | continue; 30 | } 31 | 32 | visitedAncestors.Pop(); 33 | } 34 | 35 | ret.Add(current); 36 | System.Console.WriteLine(current.GetPath()); // Process the node 37 | toVisit.Pop(); 38 | } 39 | 40 | return ret; 41 | } 42 | 43 | /// 44 | /// Return the top element of stack or null if the Stack is empty. 45 | /// 46 | /// 47 | /// 48 | private static Node PeekOrDefault(Stack s) 49 | { 50 | return s.Count == 0 ? null : s.Peek(); 51 | } 52 | 53 | /// 54 | /// Push all children of a given node in reverse order into the 55 | /// . 56 | /// 57 | /// Use this to traverse the tree from left to right. 58 | /// 59 | /// 60 | /// 61 | private static void PushReverse(Stack s, List list) 62 | { 63 | foreach (var l in list.ToArray().Reverse()) 64 | { 65 | s.Push(l); 66 | } 67 | } 68 | 69 | /// 70 | /// Push all children of a given node in givrn order into the 71 | /// . 72 | /// 73 | /// Use this to traverse the tree from right to left. 74 | /// 75 | /// 76 | /// 77 | private static void PushNonReverse(this Stack s, List list) 78 | { 79 | foreach (var l in list.ToArray()) 80 | { 81 | s.Push(l); 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /source/TreeLibDemoLib/Development/PostOrderV2.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibDemoLib.Development 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | /// 8 | /// This code shows the second development version of the PostOrder 9 | /// traversal algorithm. It combines the code: 10 | /// 1) Published by Dave Remy in his 2010 RemLog blog at: 11 | /// https://blogs.msdn.microsoft.com/daveremy/2010/03/16/non-recursive-post-order-depth-first-traversal-in-c/ 12 | /// 13 | /// 2) With the "Generic Tree and Linked List Traversal in C#" post by Mike Adelson 14 | /// http://www.codeducky.org/easy-tree-and-linked-list-traversal-in-c/ 15 | /// 16 | static public class PostOrderV2 17 | { 18 | /// 19 | /// Provides a Generic implementaion for a DepthFirst (Post-Order) 20 | /// Traversal algorithm, which can be used to traverse a n-ary tree 21 | /// via foreach(var item in collection){ ... } 22 | /// 23 | /// 24 | /// 25 | /// 26 | /// 27 | public static IEnumerable Traverse( 28 | T root 29 | , Func> children) 30 | { 31 | if (children == null) 32 | throw new ArgumentNullException(nameof(children)); 33 | 34 | return PostOrderIterator(root, children); 35 | } 36 | 37 | private static IEnumerable PostOrderIterator( 38 | T root 39 | , Func> children) 40 | { 41 | var toVisit = new Stack(); 42 | var visitedAncestors = new Stack(); 43 | 44 | toVisit.Push(root); 45 | while (toVisit.Count > 0) 46 | { 47 | var node = toVisit.Peek(); 48 | 49 | if (children(node).FirstOrDefault() != null) 50 | { 51 | if (node.Equals(PeekOrDefault(visitedAncestors)) == false) 52 | { 53 | visitedAncestors.Push(node); 54 | PushReverse(toVisit, children(node)); 55 | continue; 56 | } 57 | 58 | visitedAncestors.Pop(); 59 | } 60 | 61 | yield return node; // Process the node 62 | toVisit.Pop(); 63 | } 64 | } 65 | 66 | 67 | /// 68 | /// Return the top element of stack or null if the Stack is empty. 69 | /// 70 | /// 71 | /// 72 | private static T PeekOrDefault(Stack s) 73 | { 74 | return s.Count == 0 ? default(T) : s.Peek(); 75 | } 76 | 77 | /// 78 | /// Push all children of a given node in reverse order into the 79 | /// . 80 | /// 81 | /// Use this to traverse the tree from left to right. 82 | /// 83 | /// 84 | /// 85 | private static void PushReverse(Stack s, IEnumerable list) 86 | { 87 | foreach (var l in list.ToArray().Reverse()) 88 | { 89 | s.Push(l); 90 | } 91 | } 92 | 93 | /// 94 | /// Push all children of a given node in givrn order into the 95 | /// . 96 | /// 97 | /// Use this to traverse the tree from right to left. 98 | /// 99 | /// 100 | /// 101 | private static void PushNonReverse(Stack s, IEnumerable list) 102 | { 103 | foreach (var l in list.ToArray()) 104 | { 105 | s.Push(l); 106 | } 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /source/TreeLibDemoLib/Development/PreOrderV1.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibDemoLib.Development 2 | { 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// Source: http://urosv.blogspot.de/2011/04/iterative-binary-tree-traversal.html 7 | /// C/C++ Blog Post by: Uros Vidojevic 8 | /// 9 | /// Provides a basic sample implementation that traverses a tree in (Depth-First) 10 | /// PreOrder Fashion. 11 | /// 12 | public static class PreOrderV1 13 | { 14 | /// 15 | /// Source: http://urosv.blogspot.de/2011/04/iterative-binary-tree-traversal.html 16 | /// C/C++ Blog Post by: Uros Vidojevic 17 | /// 18 | /// 19 | /// 20 | public static List Traverse(Node root) 21 | { 22 | List ret = new List(); 23 | var stack = new Stack(); 24 | stack.Push(root); 25 | 26 | while (stack.Count > 0) 27 | { 28 | var current = stack.Pop(); 29 | 30 | ret.Add(current); 31 | System.Console.WriteLine(current.GetPath()); // Process the node 32 | 33 | for (int i = current.Children.Count - 1; i >= 0; i--) 34 | { 35 | stack.Push(current.Children[i]); 36 | } 37 | } 38 | 39 | return ret; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /source/TreeLibDemoLib/Development/PreOrderV2.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibDemoLib.Development 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | /// 8 | /// Source: 9 | /// http://www.codeducky.org/easy-tree-and-linked-list-traversal-in-c/ 10 | /// https://github.com/madelson/MedallionUtilities/blob/master/MedallionCollections/Traverse.cs 11 | /// by Mike Adelson 12 | /// 13 | /// Provides a fist generic implementation that traverses a tree in (Depth-First) 14 | /// PreOrder Fashion. 15 | /// 16 | public static class PreOrderV2 17 | { 18 | /// 19 | /// Provides a Generic implementaion for a DepthFirst (Pre-Order) 20 | /// Traversal algorithm, which can be used to traverse a n-ary tree 21 | /// via foreach(var item in collection){ ... } 22 | /// 23 | /// 24 | /// 25 | /// 26 | /// 27 | public static IEnumerable Traverse(T root, Func> children) 28 | { 29 | if (children == null) 30 | throw new ArgumentNullException(nameof(children)); 31 | 32 | return TraverseIterator(root, children); 33 | } 34 | 35 | private static IEnumerable TraverseIterator(T root, Func> children) 36 | { 37 | var stack = new Stack(); 38 | stack.Push(root); 39 | 40 | while (stack.Count > 0) 41 | { 42 | var next = stack.Pop(); 43 | yield return next; 44 | 45 | foreach (var child in children(next).ToArray().Reverse()) 46 | { 47 | stack.Push(child); 48 | } 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /source/TreeLibDemoLib/Node.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibDemoLib 2 | { 3 | using System.Collections.Generic; 4 | 5 | public class Node 6 | { 7 | public string Id; 8 | public List Children; 9 | public Node Parent; 10 | 11 | public Node(Node parent, string id) 12 | { 13 | Parent = parent; 14 | Id = id; 15 | Children = new List(); 16 | } 17 | 18 | public Node(Node parent, string id, List children) 19 | { 20 | Parent = parent; 21 | Id = id; 22 | Children = children; 23 | } 24 | 25 | public override bool Equals(object obj) 26 | { 27 | var node = obj as Node; 28 | if (node != null) 29 | { 30 | return node.Id == this.Id; 31 | } 32 | return false; 33 | } 34 | 35 | public override int GetHashCode() 36 | { 37 | return Id.GetHashCode(); 38 | } 39 | 40 | public string GetPath(Node current = null) 41 | { 42 | if (current == null) 43 | current = this; 44 | 45 | string result = string.Empty; 46 | 47 | // Traverse the list of parents backwards and 48 | // add each child to the path 49 | while (current != null) 50 | { 51 | result = "/" + current.Id + result; 52 | 53 | current = current.Parent; 54 | } 55 | 56 | return result; 57 | } 58 | 59 | public override string ToString() 60 | { 61 | if (Id == null) 62 | return "(null)"; 63 | 64 | if (Id == string.Empty) 65 | return "(empty)"; 66 | 67 | if (Parent == null) 68 | return Id; 69 | 70 | return string.Format("{0} at: {1}", Id, GetPath()); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /source/TreeLibDemoLib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("TreeLibDemoLib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TreeLibDemoLib")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a2328c9b-04ec-4b79-a6f3-5a0b3fd7d3ac")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /source/TreeLibDemoLib/TreeLibDemoLib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {A2328C9B-04EC-4B79-A6F3-5A0B3FD7D3AC} 8 | Library 9 | Properties 10 | TreeLibDemoLib 11 | TreeLibDemoLib 12 | v4.5.2 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /source/TreeLibNet/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("TreeLibNet")] 8 | [assembly: AssemblyDescription("https://github.com/Dirkster99/TreeLib")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("TreeLibNet")] 12 | [assembly: AssemblyCopyright("Copyright © 2017-2019")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("882e7e61-8000-4396-9067-0a5b25258bd4")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.2.0.0")] 35 | [assembly: AssemblyFileVersion("1.2.0.0")] 36 | -------------------------------------------------------------------------------- /source/TreeLibNet/TreeLibNet.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {882E7E61-8000-4396-9067-0A5B25258BD4} 8 | Library 9 | Properties 10 | TreeLib 11 | TreeLib 12 | v4.0 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | bin\Debug\TreeLib.xml 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | bin\Release\TreeLib.xml 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /source/TreeLibNugetDemo/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /source/TreeLibNugetDemo/Demos/Directories/DirSizeWoException.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibNugetDemo.Demos.Directories 2 | { 3 | using System; 4 | using System.IO; 5 | 6 | /// 7 | /// Demonstrates a directory traversal method build on to the IEnumerable/Yield 8 | /// implementation. This implementation does NOT SUPPORT exception handling 9 | /// - which can be verified here. 10 | /// 11 | /// See (see class for a Generic implementation 12 | /// with support for exception handling. 13 | /// 14 | public class DirSizeWoException 15 | { 16 | /// 17 | /// Implements a simple user interaction to ask for a directory to traverse 18 | /// and compute statistics for. 19 | /// 20 | public static void DemoDirectoryTreeTraversal() 21 | { 22 | Console.WriteLine(); 23 | Console.WriteLine(); 24 | Console.WriteLine(); 25 | Console.WriteLine("This demo visits (traverses) all sub-directories of a"); 26 | Console.WriteLine("given directory and output the size of all files in the end."); 27 | Console.WriteLine(); 28 | Console.WriteLine("Please input a path e.g. 'C:' (without quotes) or just press enter if you"); 29 | Console.WriteLine("do not want to see this demo right now."); 30 | 31 | string path = Console.ReadLine(); 32 | 33 | if (string.IsNullOrEmpty(path) == true) 34 | return; 35 | 36 | if (path.Length == 2) // Change 'C:' into 'C:\' to make sure its a valid path 37 | { 38 | if (path[1] == ':') 39 | path += '\\'; 40 | } 41 | 42 | long files =0; 43 | long folders = 0; 44 | long size = DirSizeWoException.ComputeDirSize(path, out files, out folders); 45 | 46 | double kBSize = size / 1024; 47 | double mBSize = size / 1024 / 1024; 48 | double gBSize = size / 1024 / 1024 / 1024; 49 | Console.WriteLine(); 50 | Console.WriteLine(); 51 | Console.WriteLine(" Folders found: {0}", folders); 52 | Console.WriteLine(" Files found: {0}", files); 53 | Console.WriteLine("Directory Size is: {0} Kb, {1} Mb, {2} Gb", kBSize, mBSize, gBSize); 54 | Console.WriteLine(); 55 | Console.WriteLine(); 56 | Console.WriteLine(); 57 | Console.WriteLine(); 58 | } 59 | 60 | /// 61 | /// This method traverses the sub-directory structure of 62 | /// the directory to compute the 63 | /// size of all files that are stored in this directory. 64 | /// 65 | /// This equivalent to the recursive implementation as explained here: 66 | /// https://stackoverflow.com/questions/468119/whats-the-best-way-to-calculate-the-size-of-a-directory-in-net#468131 67 | /// 68 | /// But this will fail if we encounter an exception: 69 | /// https://stackoverflow.com/questions/1738820/a-problem-with-exception-handling-for-ienumerablet-its-lazyness-dependent#1738856 70 | /// 71 | /// See class for generic traversal 72 | /// INCLUDING Exception handling. 73 | /// 74 | /// 75 | /// 76 | private static long ComputeDirSize(string sdirRoot, out long files 77 | , out long folders) 78 | { 79 | long size = files = folders = 0; 80 | 81 | try 82 | { 83 | var dirRoot = new System.IO.DirectoryInfo(sdirRoot); 84 | 85 | var levorderItems = TreeLib.BreadthFirst.Traverse.LevelOrder(dirRoot, i => i.GetDirectories()); 86 | Console.WriteLine(); 87 | 88 | foreach (var current in levorderItems) 89 | { 90 | folders++; 91 | 92 | ////// Use this to print level depth and name of each visited directory 93 | ////Console.WriteLine(string.Format("{0,4}-{1}", current.Level 94 | //// , current.Node.FullName)); 95 | 96 | Console.Write("."); // print a simple progress indicator 97 | 98 | FileInfo[] fis = current.Node.GetFiles(); 99 | foreach (FileInfo fi in fis) 100 | { 101 | files++; 102 | size = size + fi.Length; 103 | } 104 | } 105 | } 106 | catch (Exception e) 107 | { 108 | Console.WriteLine(); 109 | Console.WriteLine("Cannot complete enumeration.'"); 110 | Console.WriteLine("An unexpected error occured: '{0}'", e.Message); 111 | Console.WriteLine(); 112 | Console.WriteLine("Press any key..."); 113 | Console.ReadKey(); 114 | } 115 | 116 | return size; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /source/TreeLibNugetDemo/Demos/Directories/DirectorySize.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibNugetDemo.Demos.Directories 2 | { 3 | using System; 4 | using System.IO; 5 | using TreeLib.BreadthFirst; 6 | 7 | /// 8 | /// Demonstrates a directory traversal method build on to the Generic<T, TResult> 9 | /// class implementation. This implementation SUPPORTS EXCEPTION handling 10 | /// - which can be verified here. 11 | /// 12 | /// See (see class for an IEnumerable/Yield 13 | /// implementation without support for exception handling. 14 | /// 15 | public class DirectorySize 16 | { 17 | /// 18 | /// Implements a method that computes statistics 19 | /// (number of folders, files, and their size) 20 | /// for each directory in . 21 | /// 22 | /// 23 | /// 24 | /// 25 | private static DirSizeResult ComputeDirSize(DirSizeResult res, DirectoryInfo d) 26 | { 27 | res.Folders++; 28 | 29 | try 30 | { 31 | FileInfo[] fis = d.GetFiles(); 32 | foreach (FileInfo fi in fis) 33 | { 34 | res.Files++; 35 | res.Size += fi.Length; 36 | } 37 | } 38 | catch 39 | { 40 | // No access to files could be handled here ... 41 | Console.Write("F"); 42 | } 43 | 44 | return res; 45 | } 46 | 47 | /// 48 | /// Implements a simple user interaction to ask for a directory to traverse 49 | /// and compute statistics for. 50 | /// 51 | public static void DemoDirectoryTreeTraversal() 52 | { 53 | Console.WriteLine(); 54 | Console.WriteLine(); 55 | Console.WriteLine(); 56 | Console.WriteLine("This demo visits (traverses) all sub-directories of a"); 57 | Console.WriteLine("given directory and outputs the size of all files in the end."); 58 | Console.WriteLine(); 59 | Console.WriteLine("Please input a path e.g. 'C:' (without quotes) or just press enter if you"); 60 | Console.WriteLine("do not want to see this demo right now."); 61 | 62 | string path = Console.ReadLine(); 63 | 64 | if (string.IsNullOrEmpty(path) == true) 65 | return; 66 | 67 | if (path.Length == 2) // Change 'C:' into 'C:\' to make sure its a valid path 68 | { 69 | if (path[1] == ':') 70 | path += '\\'; 71 | } 72 | 73 | var res = new DirSizeResult(); // Initialize result object 74 | 75 | // You can use LevelOrder, PostOrder, and PreOrder here 76 | var Order = new LevelOrder(); 77 | 78 | res = Order.Traverse(new DirectoryInfo(path) 79 | , i => i.GetDirectories() 80 | , res 81 | , ComputeDirSize 82 | 83 | , i => Console.Write(".") // print a simple progress indicator 84 | 85 | , (i, exc, j) => // print a simple child exception indicator 86 | { Console.Write("D"); return i; } 87 | ); 88 | 89 | double kBSize = res.Size / 1024; 90 | double mBSize = res.Size / 1024 / 1024; 91 | double gBSize = res.Size / 1024 / 1024 / 1024; 92 | Console.WriteLine(); 93 | Console.WriteLine(); 94 | Console.WriteLine(" Folders found: {0}", res.Folders); 95 | Console.WriteLine(" Files found: {0}", res.Files); 96 | Console.WriteLine("Directory Size is: {0} Kb, {1} Mb, {2} Gb", kBSize, mBSize, gBSize); 97 | Console.WriteLine(); 98 | Console.WriteLine(); 99 | Console.WriteLine(); 100 | } 101 | 102 | #region private class 103 | private class DirSizeResult 104 | { 105 | public DirSizeResult() 106 | { 107 | Size = Folders = Files = 0; 108 | } 109 | 110 | public long Size { get; set; } 111 | 112 | public long Folders { get; set; } 113 | 114 | public long Files { get; set; } 115 | } 116 | #endregion private class 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /source/TreeLibNugetDemo/Demos/Node.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibNugetDemo.Demos 2 | { 3 | using System.Collections.Generic; 4 | 5 | class Node 6 | { 7 | public string Id; 8 | public List Children; 9 | public Node Parent; 10 | 11 | public Node(Node parent, string id) 12 | { 13 | Parent = parent; 14 | Id = id; 15 | Children = new List(); 16 | } 17 | 18 | public Node(Node parent, string id, List children) 19 | { 20 | Parent = parent; 21 | Id = id; 22 | Children = children; 23 | } 24 | 25 | public override bool Equals(object obj) 26 | { 27 | var node = obj as Node; 28 | if (node != null) 29 | { 30 | return node.Id == this.Id; 31 | } 32 | return false; 33 | } 34 | 35 | public override int GetHashCode() 36 | { 37 | return Id.GetHashCode(); 38 | } 39 | 40 | public string GetPath(Node current = null) 41 | { 42 | if (current == null) 43 | current = this; 44 | 45 | string result = string.Empty; 46 | 47 | // Traverse the list of parents backwards and 48 | // add each child to the path 49 | while (current != null) 50 | { 51 | result = "/" + current.Id + result; 52 | 53 | current = current.Parent; 54 | } 55 | 56 | return result; 57 | } 58 | 59 | public override string ToString() 60 | { 61 | if (Id == null) 62 | return "(null)"; 63 | 64 | if (Id == string.Empty) 65 | return "(empty)"; 66 | 67 | if (Parent == null) 68 | return Id; 69 | 70 | return string.Format("{0} at: {1}", Id, GetPath()); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /source/TreeLibNugetDemo/Demos/PrintMenu.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibNugetDemo.Demos 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | internal class PrintMenu 7 | { 8 | #region fields 9 | private readonly List _Menu = new List(); 10 | #endregion fields 11 | 12 | #region ctors 13 | public PrintMenu() 14 | { 15 | } 16 | #endregion ctors 17 | 18 | #region methods 19 | internal void AddMenuEntry(char key, string caption) 20 | { 21 | _Menu.Add(new MapMenu(key, caption)); 22 | } 23 | 24 | internal char ShowMenu() 25 | { 26 | Console.WriteLine(); 27 | Console.WriteLine(); 28 | 29 | foreach (var item in _Menu) 30 | { 31 | Console.WriteLine("Key: '{0}' {1}", item.Key, item.Caption); 32 | } 33 | 34 | Console.WriteLine(); 35 | Console.WriteLine("Press a menu key to see that demo or any other for exit."); 36 | Console.WriteLine(); 37 | 38 | return Console.ReadKey().KeyChar; 39 | } 40 | #endregion methods 41 | 42 | #region private classes 43 | private class MapMenu 44 | { 45 | public MapMenu(char key, string caption) 46 | { 47 | Key = key; 48 | Caption = caption; 49 | } 50 | 51 | public char Key { get; private set; } 52 | 53 | public string Caption { get; private set; } 54 | } 55 | #endregion private classes 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /source/TreeLibNugetDemo/Demos/TraversalDemo.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibNugetDemo.Demos 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | internal class TraversalDemo 7 | { 8 | /// 9 | /// Demos all 3 Development versions of the LevelOrder Tree Traversal algorithm 10 | /// in one method. 11 | /// 12 | /// Only the algorithm in the TreeLib library is suppossed to be 13 | /// final - all other version are kept to understand the principal applied to 14 | /// arrive at the Generic patterns in the TreeLib library. 15 | /// 16 | /// 17 | internal static void TestLevelOrder(Node root) 18 | { 19 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX LevelOrder (Breadth-First) 20 | Console.WriteLine("LevelOrderTraversal Tree Traversal"); 21 | var levorderItems = TreeLib.BreadthFirst.Traverse.LevelOrder(root, i => i.Children); 22 | 23 | foreach (var current in levorderItems) 24 | { 25 | Console.WriteLine(string.Format("{0,4} - {1}", current.Level 26 | , current.Node.GetPath())); 27 | } 28 | 29 | Console.WriteLine(); 30 | Console.WriteLine(); 31 | Console.WriteLine(); 32 | } 33 | 34 | /// 35 | /// Demos all 3 Development versions of the PreOrder Tree Traversal algorithm 36 | /// in one method. 37 | /// 38 | /// Only the algorithm in the TreeLib library is suppossed to be 39 | /// final - all other version are kept to understand the principal applied to 40 | /// arrive at the Generic patterns in the TreeLib library. 41 | /// 42 | /// 43 | internal static void TestPreOrder(Node root) 44 | { 45 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 46 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX PreOrder Traversal (Depth-First) 47 | Console.WriteLine("PreOrder (Depth First) Tree Traversal"); 48 | var items = TreeLib.Depthfirst.Traverse.Preorder(root, i => i.Children); 49 | foreach (var item in items) 50 | { 51 | Console.WriteLine(item.GetPath()); 52 | } 53 | Console.WriteLine(); 54 | Console.WriteLine("Press any key for PreOrder demo with multiple roots..."); 55 | Console.ReadKey(); 56 | Console.WriteLine(); 57 | Console.WriteLine(); 58 | 59 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX PreOrder Traversal (Depth-First) 60 | Console.WriteLine("PreOrder (Depth First) Tree Traversal (Multiple Roots Nodes)"); 61 | 62 | var root1 = makeTree(1); 63 | var root2 = makeTree(1); 64 | var multipleRoots = new List() { root2, root1 }.GetEnumerator(); 65 | 66 | items = TreeLib.Depthfirst.Traverse.Preorder(multipleRoots, i => i.Children); 67 | foreach (var item in items) 68 | { 69 | Console.WriteLine(item.GetPath()); 70 | } 71 | Console.WriteLine(); 72 | Console.WriteLine(); 73 | Console.WriteLine(); 74 | } 75 | 76 | /// 77 | /// Demos all 3 Development versions of the PostOrder Tree Traversal algorithm 78 | /// in one method. 79 | /// 80 | /// Only the algorithm in the TreeLib library is suppossed to be 81 | /// final - all other version are kept to understand the principal applied to 82 | /// arrive at the Generic patterns in the TreeLib library. 83 | /// 84 | /// 85 | internal static void TestPostOrder(Node root) 86 | { 87 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 88 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX PostOrder Traversal (Depth-First) 89 | Console.WriteLine("(Depth First) PostOrder Tree Traversal"); 90 | var items = TreeLib.Depthfirst.Traverse.PostOrder(root, i => i.Children); 91 | 92 | foreach (var item in items) 93 | { 94 | Console.WriteLine(item.GetPath()); 95 | } 96 | Console.WriteLine(); 97 | Console.WriteLine(); 98 | Console.WriteLine(); 99 | } 100 | 101 | /// 102 | /// Returns a simple tree of to work 103 | /// with the demo code in this application. 104 | /// 105 | /// a 106 | /// / | \ 107 | /// b c d 108 | /// /|\ \ \ \ 109 | /// e,f,xyz g h i 110 | /// 111 | /// dfs: efbgchida 112 | /// 113 | /// 114 | internal static Node makeTree(int isampleNumber = 0) 115 | { 116 | string SampleIndicator = string.Empty; 117 | 118 | if (isampleNumber > 0) 119 | SampleIndicator = isampleNumber.ToString(); 120 | 121 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 122 | 123 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 124 | var c = new Node(a, string.Format("c{0}", SampleIndicator)); 125 | var d = new Node(a, string.Format("d{0}", SampleIndicator)); 126 | a.Children.Add(b); 127 | a.Children.Add(c); 128 | a.Children.Add(d); 129 | 130 | b.Children.Add(new Node(b, string.Format("e{0}", SampleIndicator))); 131 | b.Children.Add(new Node(b, string.Format("f{0}", SampleIndicator))); 132 | b.Children.Add(new Node(b, string.Format("x{0}", SampleIndicator))); 133 | b.Children.Add(new Node(b, string.Format("y{0}", SampleIndicator))); 134 | b.Children.Add(new Node(b, string.Format("z{0}", SampleIndicator))); 135 | 136 | c.Children.Add(new Node(c, string.Format("g{0}", SampleIndicator))); 137 | 138 | d.Children.Add(new Node(d, string.Format("h{0}", SampleIndicator))); 139 | d.Children.Add(new Node(d, string.Format("i{0}", SampleIndicator))); 140 | 141 | return a; 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /source/TreeLibNugetDemo/Program.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibNugetDemo 2 | { 3 | using System; 4 | using TreeLibNugetDemo.Demos; 5 | using TreeLibNugetDemo.Demos.Directories; 6 | 7 | /// 8 | /// This demo application tests different versions of tree traversal algorithms from 9 | /// the Nuget Dirster.TreeLib package (you may have to enable/restore NuGet packaging). 10 | /// 11 | class Program 12 | { 13 | static int Main(string[] args) 14 | { 15 | PrintMenu menu = new PrintMenu(); 16 | var root = TraversalDemo.makeTree(); 17 | 18 | menu.AddMenuEntry('1', "Level Order Traversal Demo"); 19 | menu.AddMenuEntry('2', "Pre-Order Traversal Demo"); 20 | menu.AddMenuEntry('3', "Post-Order Traversal Demo"); 21 | menu.AddMenuEntry('4', "Compute Directory Size (without exception handling in enumeration)"); 22 | menu.AddMenuEntry('5', "Compute Directory Size (WITH exception handling and Generic class)"); 23 | 24 | while (true) 25 | { 26 | Console.WriteLine(); 27 | Console.WriteLine("This program demos TreeLib applications and use cases by example."); 28 | var key = menu.ShowMenu(); 29 | 30 | Console.WriteLine(); 31 | Console.WriteLine(); 32 | Console.WriteLine(); 33 | Console.WriteLine(); 34 | 35 | switch (key) 36 | { 37 | case '1': 38 | TraversalDemo.TestLevelOrder(root); 39 | break; 40 | 41 | case '2': 42 | TraversalDemo.TestPreOrder(root); 43 | break; 44 | 45 | case '3': 46 | TraversalDemo.TestPostOrder(root); 47 | break; 48 | 49 | case '4': 50 | DirSizeWoException.DemoDirectoryTreeTraversal(); 51 | break; 52 | 53 | case '5': 54 | DirectorySize.DemoDirectoryTreeTraversal(); 55 | break; 56 | default: 57 | return (0); 58 | } 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /source/TreeLibNugetDemo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("TreeLibNugetDemo")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TreeLibNugetDemo")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("607b4973-e3db-4071-83c6-ddf301d39a32")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /source/TreeLibNugetDemo/TreeLibNugetDemo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {607B4973-E3DB-4071-83C6-DDF301D39A32} 8 | Exe 9 | TreeLibNugetDemo 10 | TreeLibNugetDemo 11 | v4.5.2 12 | 512 13 | true 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | ..\packages\Dirkster.TreeLib.1.2.0\lib\net40\TreeLib.dll 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /source/TreeLibNugetDemo/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /source/TreeLibNugetUnitTests/CoreTests.cs: -------------------------------------------------------------------------------- 1 | namespace TreeLibNugetUnitTests 2 | { 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using TreeLibDemoLib; 8 | using TreeLibDemoLib.Development; 9 | 10 | [TestClass] 11 | public class CoreTests 12 | { 13 | [TestMethod] 14 | public void TestMethod1() 15 | { 16 | var root = CoreTests.makeTree1(); 17 | TestTreeTraversal(root); 18 | } 19 | 20 | [TestMethod] 21 | public void TestMethod2() 22 | { 23 | var root = CoreTests.makeTree2(); 24 | TestTreeTraversal(root); 25 | } 26 | 27 | [TestMethod] 28 | public void TestMethod3() 29 | { 30 | var root = CoreTests.makeTree3(); 31 | TestTreeTraversal(root); 32 | } 33 | 34 | [TestMethod] 35 | public void TestMethod4() 36 | { 37 | var root = CoreTests.makeTree4(); 38 | TestTreeTraversal(root); 39 | } 40 | 41 | [TestMethod] 42 | public void TestMethod5() 43 | { 44 | var root = CoreTests.makeTree5(); 45 | TestTreeTraversal(root); 46 | } 47 | 48 | [TestMethod] 49 | public void TestMethod6() 50 | { 51 | var root = CoreTests.makeTree6(); 52 | TestTreeTraversal(root); 53 | } 54 | 55 | [TestMethod] 56 | public void TestMethod7() 57 | { 58 | var root = CoreTests.makeTree7(); 59 | TestTreeTraversal(root); 60 | } 61 | 62 | [TestMethod] 63 | public void TestMethod8() 64 | { 65 | var root = CoreTests.makeTree8(); 66 | TestTreeTraversal(root); 67 | } 68 | 69 | [TestMethod] 70 | public void TestMethod9() 71 | { 72 | var root = CoreTests.makeTree9(); 73 | TestTreeTraversal(root); 74 | } 75 | 76 | [TestMethod] 77 | public void TestMethod10() 78 | { 79 | var root = CoreTests.makeTree10(); 80 | TestTreeTraversal(root); 81 | } 82 | 83 | [TestMethod] 84 | public void TestMethod11() 85 | { 86 | var root = CoreTests.makeTree11(); 87 | TestTreeTraversal(root); 88 | } 89 | 90 | [TestMethod] 91 | public void TestMethod12() 92 | { 93 | var root = CoreTests.makeTree12(); 94 | TestTreeTraversal(root); 95 | } 96 | 97 | [TestMethod] 98 | public void TestMethod13() 99 | { 100 | var root = CoreTests.makeTree13(); 101 | TestTreeTraversal(root); 102 | } 103 | 104 | private static void TestTreeTraversal(Node root) 105 | { 106 | // Generate version 1 traversals 107 | var levelOrderItems1 = LevelOrderV1.Traverse(root); 108 | var preOrderItems1 = PreOrderV1.Traverse(root); 109 | var postOrderItems1 = PostOrderV1.Traverse(root); 110 | 111 | // Generate version 2 traversals 112 | var levelOrderItems2 = LevelOrderV2.Traverse(root, i => i.Children).ToList(); 113 | var preOrderItems2 = PreOrderV2.Traverse(root, i => i.Children).ToList(); 114 | var postOrderItems2 = PostOrderV2.Traverse(root, i => i.Children).ToList(); 115 | 116 | // Generate version 3 traversals 117 | var levelOrderItems3 = TreeLib.BreadthFirst.Traverse.LevelOrder(root, i => i.Children).ToList(); 118 | var preOrderItems3 = TreeLib.Depthfirst.Traverse.Preorder(root, i => i.Children).ToList(); 119 | 120 | List postOrderItems3 = null; 121 | try 122 | { 123 | postOrderItems3 = TreeLib.Depthfirst.Traverse.PostOrder(root, i => i.Children).ToList(); 124 | } 125 | catch (Exception exc) 126 | { 127 | Console.WriteLine(exc.Message); 128 | Console.WriteLine(exc.StackTrace); 129 | } 130 | 131 | // Order of traversal may be different, 132 | // in the end, all elements are there (count) 133 | Assert.AreEqual(levelOrderItems1.Count, preOrderItems1.Count); 134 | Assert.AreEqual(levelOrderItems1.Count, postOrderItems1.Count); 135 | 136 | Assert.AreEqual(levelOrderItems1.Count, levelOrderItems2.Count); 137 | Assert.AreEqual(preOrderItems1.Count, preOrderItems2.Count); 138 | Assert.AreEqual(postOrderItems1.Count, postOrderItems2.Count); 139 | 140 | Assert.AreEqual(levelOrderItems1.Count, levelOrderItems3.Count); 141 | Assert.AreEqual(preOrderItems1.Count, preOrderItems3.Count); 142 | Assert.AreEqual(postOrderItems1.Count, postOrderItems3.Count); 143 | 144 | // Ensure same sequence on each version 1 and 2 returned 145 | for (int i = 0; i < levelOrderItems1.Count; i++) 146 | Assert.AreEqual(levelOrderItems1[i], levelOrderItems2[i].Item2); 147 | 148 | for (int i = 0; i < preOrderItems1.Count; i++) 149 | Assert.AreEqual(preOrderItems1[i], preOrderItems2[i]); 150 | 151 | for (int i = 0; i < postOrderItems1.Count; i++) 152 | Assert.AreEqual(postOrderItems1[i], postOrderItems2[i]); 153 | 154 | // Ensure same sequence on each version 1 and 3 returned 155 | for (int i = 0; i < levelOrderItems1.Count; i++) 156 | Assert.AreEqual(levelOrderItems1[i], levelOrderItems3[i].Node); 157 | 158 | for (int i = 0; i < preOrderItems1.Count; i++) 159 | Assert.AreEqual(preOrderItems1[i], preOrderItems3[i]); 160 | 161 | for (int i = 0; i < postOrderItems1.Count; i++) 162 | Assert.AreEqual(postOrderItems1[i], postOrderItems3[i]); 163 | 164 | // Sort Version 1 by Id and make sure all items are there 165 | levelOrderItems1.Sort((i1, i2) => i1.Id.CompareTo(i2.Id)); 166 | preOrderItems1.Sort((i1, i2) => i1.Id.CompareTo(i2.Id)); 167 | postOrderItems1.Sort((i1, i2) => i1.Id.CompareTo(i2.Id)); 168 | 169 | // Sort Version 2 by Id and make sure all items are there 170 | levelOrderItems2.Sort((i1, i2) => i1.Item2.Id.CompareTo(i2.Item2.Id)); 171 | preOrderItems2.Sort((i1, i2) => i1.Id.CompareTo(i2.Id)); 172 | postOrderItems2.Sort((i1, i2) => i1.Id.CompareTo(i2.Id)); 173 | 174 | // Sort Version 3 by Id and make sure all items are there 175 | levelOrderItems3.Sort((i1, i2) => i1.Node.Id.CompareTo(i2.Node.Id)); 176 | preOrderItems3.Sort((i1, i2) => i1.Id.CompareTo(i2.Id)); 177 | postOrderItems3.Sort((i1, i2) => i1.Id.CompareTo(i2.Id)); 178 | 179 | for (int i = 0; i < levelOrderItems1.Count; i++) 180 | { 181 | Assert.AreEqual(levelOrderItems1[i], preOrderItems1[i]); 182 | Assert.AreEqual(levelOrderItems1[i], postOrderItems1[i]); 183 | 184 | if (levelOrderItems1[i].Equals(levelOrderItems2[i].Item2) == false) 185 | { 186 | Console.WriteLine("1.1) Comparing levelOrderItems1[i] '{0}' with levelOrderItems2[i] '{1}' failed." 187 | , levelOrderItems1[i], levelOrderItems2[i].Item2); 188 | } 189 | 190 | if (preOrderItems1[i].Equals(preOrderItems2[i]) == false) 191 | { 192 | Console.WriteLine("2.1) Comparing preOrderItems1[i] '{0}' with preOrderItems2[i] '{1}' failed." 193 | , preOrderItems1[i], preOrderItems2[i]); 194 | } 195 | 196 | if (postOrderItems1[i].Equals(postOrderItems2[i]) == false) 197 | { 198 | Console.WriteLine("3.1) Comparing postOrderItems1[i] '{0}' with postOrderItems2[i] '{1}' failed." 199 | , postOrderItems1[i], postOrderItems2[i]); 200 | } 201 | 202 | Assert.AreEqual(levelOrderItems1[i], levelOrderItems2[i].Item2); 203 | Assert.AreEqual(preOrderItems1[i], preOrderItems2[i]); 204 | Assert.AreEqual(postOrderItems1[i], postOrderItems2[i]); 205 | 206 | if (levelOrderItems1[i].Equals(levelOrderItems3[i].Node) == false) 207 | { 208 | Console.WriteLine("1.2) Comparing levelOrderItems1[i] '{0}' with levelOrderItems3[i] '{1}' failed." 209 | , levelOrderItems1[i], levelOrderItems3[i].Node); 210 | } 211 | 212 | if (preOrderItems1[i].Equals(preOrderItems3[i]) == false) 213 | { 214 | Console.WriteLine("2.2) Comparing preOrderItems1[i] '{0}' with preOrderItems3[i] '{1}' failed." 215 | , preOrderItems1[i], preOrderItems3[i]); 216 | } 217 | 218 | if (postOrderItems1[i].Equals(postOrderItems3[i]) == false) 219 | { 220 | Console.WriteLine("3.3) Comparing postOrderItems1[i] '{0}' with postOrderItems3[i] '{1}' failed." 221 | , postOrderItems1[i], postOrderItems3[i]); 222 | } 223 | 224 | Assert.AreEqual(levelOrderItems1[i], levelOrderItems3[i].Node); 225 | Assert.AreEqual(preOrderItems1[i], preOrderItems3[i]); 226 | 227 | postOrderItems3.Sort((i1, i2) => i1.Id.CompareTo(i2.Id)); 228 | Assert.AreEqual(postOrderItems1[i], postOrderItems3[i]); 229 | } 230 | } 231 | 232 | /// 233 | /// tree: 234 | /// a 235 | /// 236 | /// 237 | /// 238 | private static Node makeTree1(int isampleNumber = 0) 239 | { 240 | string SampleIndicator = string.Empty; 241 | 242 | if (isampleNumber > 0) 243 | SampleIndicator = isampleNumber.ToString(); 244 | 245 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 246 | 247 | return a; 248 | } 249 | 250 | /// 251 | /// tree: 252 | /// a 253 | /// | 254 | /// b 255 | /// 256 | /// 257 | /// 258 | private static Node makeTree2(int isampleNumber = 0) 259 | { 260 | string SampleIndicator = string.Empty; 261 | 262 | if (isampleNumber > 0) 263 | SampleIndicator = isampleNumber.ToString(); 264 | 265 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 266 | 267 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 268 | a.Children.Add(b); 269 | 270 | return a; 271 | } 272 | 273 | /// 274 | /// tree: 275 | /// a 276 | /// / \ 277 | /// b c 278 | /// 279 | /// 280 | /// 281 | private static Node makeTree3(int isampleNumber = 0) 282 | { 283 | string SampleIndicator = string.Empty; 284 | 285 | if (isampleNumber > 0) 286 | SampleIndicator = isampleNumber.ToString(); 287 | 288 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 289 | 290 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 291 | var c = new Node(a, string.Format("c{0}", SampleIndicator)); 292 | a.Children.Add(b); 293 | a.Children.Add(c); 294 | 295 | return a; 296 | } 297 | 298 | /// 299 | /// tree: 300 | /// a 301 | /// / | \ 302 | /// b c d 303 | /// 304 | /// 305 | /// 306 | private static Node makeTree4(int isampleNumber = 0) 307 | { 308 | string SampleIndicator = string.Empty; 309 | 310 | if (isampleNumber > 0) 311 | SampleIndicator = isampleNumber.ToString(); 312 | 313 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 314 | 315 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 316 | var c = new Node(a, string.Format("c{0}", SampleIndicator)); 317 | var d = new Node(a, string.Format("d{0}", SampleIndicator)); 318 | a.Children.Add(b); 319 | a.Children.Add(c); 320 | a.Children.Add(d); 321 | 322 | return a; 323 | } 324 | 325 | /// 326 | /// tree: 327 | /// a 328 | /// / | \ 329 | /// b c d 330 | /// / 331 | /// e 332 | /// 333 | /// 334 | /// 335 | private static Node makeTree5(int isampleNumber = 0) 336 | { 337 | string SampleIndicator = string.Empty; 338 | 339 | if (isampleNumber > 0) 340 | SampleIndicator = isampleNumber.ToString(); 341 | 342 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 343 | 344 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 345 | var c = new Node(a, string.Format("c{0}", SampleIndicator)); 346 | var d = new Node(a, string.Format("d{0}", SampleIndicator)); 347 | a.Children.Add(b); 348 | a.Children.Add(c); 349 | a.Children.Add(d); 350 | 351 | b.Children.Add(new Node(b, string.Format("e{0}", SampleIndicator))); 352 | 353 | return a; 354 | } 355 | 356 | /// 357 | /// a 358 | /// / | \ 359 | /// b c d 360 | /// / \ 361 | /// e f 362 | /// 363 | /// 364 | /// 365 | private static Node makeTree6(int isampleNumber = 0) 366 | { 367 | string SampleIndicator = string.Empty; 368 | 369 | if (isampleNumber > 0) 370 | SampleIndicator = isampleNumber.ToString(); 371 | 372 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 373 | 374 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 375 | var c = new Node(a, string.Format("c{0}", SampleIndicator)); 376 | var d = new Node(a, string.Format("d{0}", SampleIndicator)); 377 | a.Children.Add(b); 378 | a.Children.Add(c); 379 | a.Children.Add(d); 380 | 381 | b.Children.Add(new Node(b, string.Format("e{0}", SampleIndicator))); 382 | b.Children.Add(new Node(b, string.Format("f{0}", SampleIndicator))); 383 | 384 | return a; 385 | } 386 | 387 | /// 388 | /// a 389 | /// / | \ 390 | /// b c d 391 | /// /|\ 392 | /// e f x 393 | /// 394 | /// 395 | /// 396 | private static Node makeTree7(int isampleNumber = 0) 397 | { 398 | string SampleIndicator = string.Empty; 399 | 400 | if (isampleNumber > 0) 401 | SampleIndicator = isampleNumber.ToString(); 402 | 403 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 404 | 405 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 406 | var c = new Node(a, string.Format("c{0}", SampleIndicator)); 407 | var d = new Node(a, string.Format("d{0}", SampleIndicator)); 408 | a.Children.Add(b); 409 | a.Children.Add(c); 410 | a.Children.Add(d); 411 | 412 | b.Children.Add(new Node(b, string.Format("e{0}", SampleIndicator))); 413 | b.Children.Add(new Node(b, string.Format("f{0}", SampleIndicator))); 414 | b.Children.Add(new Node(b, string.Format("x{0}", SampleIndicator))); 415 | 416 | return a; 417 | } 418 | 419 | /// 420 | /// a 421 | /// / \ \ 422 | /// b c d 423 | /// /|\ \ 424 | /// e f x y 425 | /// 426 | /// 427 | /// 428 | private static Node makeTree8(int isampleNumber = 0) 429 | { 430 | string SampleIndicator = string.Empty; 431 | 432 | if (isampleNumber > 0) 433 | SampleIndicator = isampleNumber.ToString(); 434 | 435 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 436 | 437 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 438 | var c = new Node(a, string.Format("c{0}", SampleIndicator)); 439 | var d = new Node(a, string.Format("d{0}", SampleIndicator)); 440 | a.Children.Add(b); 441 | a.Children.Add(c); 442 | a.Children.Add(d); 443 | 444 | b.Children.Add(new Node(b, string.Format("e{0}", SampleIndicator))); 445 | b.Children.Add(new Node(b, string.Format("f{0}", SampleIndicator))); 446 | b.Children.Add(new Node(b, string.Format("x{0}", SampleIndicator))); 447 | b.Children.Add(new Node(b, string.Format("y{0}", SampleIndicator))); 448 | 449 | return a; 450 | } 451 | 452 | /// 453 | /// a 454 | /// / \ \ 455 | /// b c d 456 | /// / /|\ \ 457 | /// e f x y z 458 | /// 459 | /// 460 | /// 461 | private static Node makeTree9(int isampleNumber = 0) 462 | { 463 | string SampleIndicator = string.Empty; 464 | 465 | if (isampleNumber > 0) 466 | SampleIndicator = isampleNumber.ToString(); 467 | 468 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 469 | 470 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 471 | var c = new Node(a, string.Format("c{0}", SampleIndicator)); 472 | var d = new Node(a, string.Format("d{0}", SampleIndicator)); 473 | a.Children.Add(b); 474 | a.Children.Add(c); 475 | a.Children.Add(d); 476 | 477 | b.Children.Add(new Node(b, string.Format("e{0}", SampleIndicator))); 478 | b.Children.Add(new Node(b, string.Format("f{0}", SampleIndicator))); 479 | b.Children.Add(new Node(b, string.Format("x{0}", SampleIndicator))); 480 | b.Children.Add(new Node(b, string.Format("y{0}", SampleIndicator))); 481 | b.Children.Add(new Node(b, string.Format("z{0}", SampleIndicator))); 482 | 483 | return a; 484 | } 485 | 486 | /// 487 | /// a 488 | /// / \ \ 489 | /// b c d 490 | /// / /|\ \ \ 491 | /// e f x y z g 492 | /// 493 | /// 494 | /// 495 | private static Node makeTree10(int isampleNumber = 0) 496 | { 497 | string SampleIndicator = string.Empty; 498 | 499 | if (isampleNumber > 0) 500 | SampleIndicator = isampleNumber.ToString(); 501 | 502 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 503 | 504 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 505 | var c = new Node(a, string.Format("c{0}", SampleIndicator)); 506 | var d = new Node(a, string.Format("d{0}", SampleIndicator)); 507 | a.Children.Add(b); 508 | a.Children.Add(c); 509 | a.Children.Add(d); 510 | 511 | b.Children.Add(new Node(b, string.Format("e{0}", SampleIndicator))); 512 | b.Children.Add(new Node(b, string.Format("f{0}", SampleIndicator))); 513 | b.Children.Add(new Node(b, string.Format("x{0}", SampleIndicator))); 514 | b.Children.Add(new Node(b, string.Format("y{0}", SampleIndicator))); 515 | b.Children.Add(new Node(b, string.Format("z{0}", SampleIndicator))); 516 | 517 | c.Children.Add(new Node(c, string.Format("g{0}", SampleIndicator))); 518 | 519 | return a; 520 | } 521 | 522 | /// 523 | /// a 524 | /// / | \ 525 | /// b c d 526 | /// / /|\ \ | | 527 | /// e f x y z g h 528 | /// 529 | /// 530 | /// 531 | private static Node makeTree11(int isampleNumber = 0) 532 | { 533 | string SampleIndicator = string.Empty; 534 | 535 | if (isampleNumber > 0) 536 | SampleIndicator = isampleNumber.ToString(); 537 | 538 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 539 | 540 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 541 | var c = new Node(a, string.Format("c{0}", SampleIndicator)); 542 | var d = new Node(a, string.Format("d{0}", SampleIndicator)); 543 | a.Children.Add(b); 544 | a.Children.Add(c); 545 | a.Children.Add(d); 546 | 547 | b.Children.Add(new Node(b, string.Format("e{0}", SampleIndicator))); 548 | b.Children.Add(new Node(b, string.Format("f{0}", SampleIndicator))); 549 | b.Children.Add(new Node(b, string.Format("x{0}", SampleIndicator))); 550 | b.Children.Add(new Node(b, string.Format("y{0}", SampleIndicator))); 551 | b.Children.Add(new Node(b, string.Format("z{0}", SampleIndicator))); 552 | 553 | c.Children.Add(new Node(c, string.Format("g{0}", SampleIndicator))); 554 | 555 | d.Children.Add(new Node(d, string.Format("h{0}", SampleIndicator))); 556 | 557 | return a; 558 | } 559 | 560 | /// 561 | /// Returns a simple tree of to work 562 | /// with the demo code in this application. 563 | /// 564 | /// a 565 | /// / | \ 566 | /// b c d 567 | /// / /|\ \ | |\ 568 | /// e f x y z g h i 569 | /// 570 | /// 571 | private static Node makeTree12(int isampleNumber = 0) 572 | { 573 | string SampleIndicator = string.Empty; 574 | 575 | if (isampleNumber > 0) 576 | SampleIndicator = isampleNumber.ToString(); 577 | 578 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 579 | 580 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 581 | var c = new Node(a, string.Format("c{0}", SampleIndicator)); 582 | var d = new Node(a, string.Format("d{0}", SampleIndicator)); 583 | a.Children.Add(b); 584 | a.Children.Add(c); 585 | a.Children.Add(d); 586 | 587 | b.Children.Add(new Node(b, string.Format("e{0}", SampleIndicator))); 588 | b.Children.Add(new Node(b, string.Format("f{0}", SampleIndicator))); 589 | b.Children.Add(new Node(b, string.Format("x{0}", SampleIndicator))); 590 | b.Children.Add(new Node(b, string.Format("y{0}", SampleIndicator))); 591 | b.Children.Add(new Node(b, string.Format("z{0}", SampleIndicator))); 592 | 593 | c.Children.Add(new Node(c, string.Format("g{0}", SampleIndicator))); 594 | 595 | d.Children.Add(new Node(d, string.Format("h{0}", SampleIndicator))); 596 | d.Children.Add(new Node(d, string.Format("i{0}", SampleIndicator))); 597 | 598 | return a; 599 | } 600 | 601 | /// 602 | /// Returns a simple tree of to work 603 | /// with the demo code in this application. 604 | /// 605 | /// a 606 | /// | 607 | /// b 608 | /// | 609 | /// c 610 | /// | 611 | /// d 612 | /// (degenerated list) 613 | /// 614 | /// 615 | private static Node makeTree13(int isampleNumber = 0) 616 | { 617 | string SampleIndicator = string.Empty; 618 | 619 | if (isampleNumber > 0) 620 | SampleIndicator = isampleNumber.ToString(); 621 | 622 | var a = new Node(null, string.Format("a{0}", SampleIndicator)); 623 | 624 | var b = new Node(a, string.Format("b{0}", SampleIndicator)); 625 | var c = new Node(b, string.Format("c{0}", SampleIndicator)); 626 | var d = new Node(c, string.Format("d{0}", SampleIndicator)); 627 | 628 | return a; 629 | } 630 | 631 | } 632 | } 633 | -------------------------------------------------------------------------------- /source/TreeLibNugetUnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("TreeLibNugetUnitTests")] 6 | [assembly: AssemblyDescription("")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("TreeLibNugetUnitTests")] 10 | [assembly: AssemblyCopyright("Copyright © 2017")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: Guid("7ecb4d90-c421-4500-817e-322281d5061f")] 17 | 18 | // [assembly: AssemblyVersion("1.0.*")] 19 | [assembly: AssemblyVersion("1.0.0.0")] 20 | [assembly: AssemblyFileVersion("1.0.0.0")] 21 | -------------------------------------------------------------------------------- /source/TreeLibNugetUnitTests/TreeLibNugetUnitTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {7ECB4D90-C421-4500-817E-322281D5061F} 8 | Library 9 | Properties 10 | TreeLibNugetUnitTests 11 | TreeLibNugetUnitTests 12 | v4.5.2 13 | 512 14 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 15.0 16 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 17 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 18 | False 19 | UnitTest 20 | 21 | 22 | 23 | 24 | 25 | true 26 | full 27 | false 28 | bin\Debug\ 29 | DEBUG;TRACE 30 | prompt 31 | 4 32 | 33 | 34 | pdbonly 35 | true 36 | bin\Release\ 37 | TRACE 38 | prompt 39 | 4 40 | 41 | 42 | 43 | ..\packages\MSTest.TestFramework.1.4.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll 44 | 45 | 46 | ..\packages\MSTest.TestFramework.1.4.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | {A2328C9B-04EC-4B79-A6F3-5A0B3FD7D3AC} 58 | TreeLibDemoLib 59 | 60 | 61 | {45414a0f-d85d-435f-95e8-e7fd6ba2716f} 62 | TreeLibDemo 63 | 64 | 65 | {882e7e61-8000-4396-9067-0a5b25258bd4} 66 | TreeLibNet 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /source/TreeLibNugetUnitTests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | --------------------------------------------------------------------------------