You can imagine a multi-level tree using the node type, which has only the following pointer and a child pointer.
The node next pointer is used to point to the next child child element, implemented as a simple linked list.
The node child pointer is used to indicate the first child of a node.
Here is a sample code that demonstrates how to do this. It does not contain error handling and is not intended to be a complete solution, but you must compile it and, if necessary, run it under the debugger to fully understand how it works.
I also added an enumeration example to show how you could iterate over tree nodes. You probably want to play around with this to get results in different orders. IF using the enumerated is too complicated for what you need, you will need to write your own simple recusive method to visit all nodes.
Note that the node type is common in this example, and I use it only to store string data. You can simply replace T with the type you want if you don't need a generic type.
using System; using System.Collections; using System.Collections.Generic; namespace Demo { sealed class Node<T> { public T Data; // Payload. public Node<T> Next; // This will point to the next sibling node (if any), forming a linked-list. public Node<T> Child; // This will point to the first child node (if any). } sealed class Tree<T>: IEnumerable<T> { public Node<T> Root; public Node<T> AddChild(Node<T> parent, T data) { parent.Child = new Node<T> { Data = data, Next = parent.Child // Prepare to place the new node at the head of the linked-list of children. }; return parent.Child; } public IEnumerator<T> GetEnumerator() { return enumerate(Root).GetEnumerator(); } private IEnumerable<T> enumerate(Node<T> root) { for (var node = root; node != null; node = node.Next) { yield return node.Data; foreach (var data in enumerate(node.Child)) yield return data; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } class Program { void run() { var tree = new Tree<string>(); tree.Root = new Node<string>{Data = "Root"}; var l1n3 = tree.AddChild(tree.Root, "L1 N3"); var l1n2 = tree.AddChild(tree.Root, "L1 N2"); var l1n1 = tree.AddChild(tree.Root, "L1 N1"); tree.AddChild(l1n1, "L2 N1 C3"); tree.AddChild(l1n1, "L2 N1 C2"); var l2n1 = tree.AddChild(l1n1, "L2 N1 C1"); tree.AddChild(l1n2, "L2 N2 C3"); tree.AddChild(l1n2, "L2 N2 C2"); tree.AddChild(l1n2, "L2 N2 C1"); tree.AddChild(l1n3, "L2 N3 C3"); tree.AddChild(l1n3, "L2 N3 C2"); tree.AddChild(l1n3, "L2 N3 C1"); tree.AddChild(l2n1, "L3 N1 C3"); tree.AddChild(l2n1, "L3 N1 C2"); tree.AddChild(l2n1, "L3 N1 C1"); tree.Print(); } static void Main() { new Program().run(); } } static class DemoUtil { public static void Print(this object self) { Console.WriteLine(self); } public static void Print(this string self) { Console.WriteLine(self); } public static void Print<T>(this IEnumerable<T> self) { foreach (var item in self) Console.WriteLine(item); } } }
(I know this is similar to Eric's answer above, and if I read this answer before writing this, I probably wouldn't have bothered - but I already wrote this, and I didn't want to just throw it away.)