├── .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 | [](https://ci.appveyor.com/project/Dirkster99/treelib)
2 | [](https://github.com/Dirkster99/TreeLib/releases/latest)
3 | [](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 |
--------------------------------------------------------------------------------