Build a simple, high performance Tree Data Structure in c# - c#

I need to create a product catalog, in tree type.
every tree node presents by a ID(string), the functions on the tree data only 2:
getChild(string ID), give a ID, get children (no need include childrens'
children), if ID is null, get all root nodes
getParent(string ID), return parent ID if have, or null if is root
Since once the tree decided, will not change, so I think put all code in static will be best.
So I start to try use Dictionary
"id": {parent:ID, child:[id2, id3, id4....]}
Since theres about 1000+ catalog, I found I quickly mess myself up, lots of mistake in the static data, and make final result on usable. Also, now I only wrote dozens and the code is looking like mess.
Please advice a way create this simple catalog tree with high performance. Thanks

Just make a class out of it.
UPDATED:
class TreeNode : IEnumerable<TreeNode>
{
private readonly Dictionary<string, TreeNode> _children =
new Dictionary<string, TreeNode>();
public readonly string ID;
public TreeNode Parent { get; private set; }
public TreeNode(string id)
{
this.ID = id;
}
public TreeNode GetChild(string id)
{
return this._children[id];
}
public void Add(TreeNode item)
{
if (item.Parent != null)
{
item.Parent._children.Remove(item.ID);
}
item.Parent = this;
this._children.Add(item.ID, item);
}
public IEnumerator<TreeNode> GetEnumerator()
{
return this._children.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public int Count
{
get { return this._children.Count; }
}
}
Usage will be fairly simple to statically define:
var tree = new TreeNode("Root")
{
new TreeNode("Category 1")
{
new TreeNode("Item 1"),
new TreeNode("Item 2"),
new TreeNode("Item 3"),
},
new TreeNode("Category 2")
{
new TreeNode("Item 1"),
new TreeNode("Item 2"),
new TreeNode("Item 3"),
new TreeNode("Item 4"),
}
};
Edit
Some more functionality for even easier creation...
public static TreeNode BuildTree(string tree)
{
var lines = tree.Split(new[] { Environment.NewLine },
StringSplitOptions.RemoveEmptyEntries);
var result = new TreeNode("TreeRoot");
var list = new List<TreeNode> { result };
foreach (var line in lines)
{
var trimmedLine = line.Trim();
var indent = line.Length - trimmedLine.Length;
var child = new TreeNode(trimmedLine);
list[indent].Add(child);
if (indent + 1 < list.Count)
{
list[indent + 1] = child;
}
else
{
list.Add(child);
}
}
return result;
}
public static string BuildString(TreeNode tree)
{
var sb = new StringBuilder();
BuildString(sb, tree, 0);
return sb.ToString();
}
private static void BuildString(StringBuilder sb, TreeNode node, int depth)
{
sb.AppendLine(node.ID.PadLeft(node.ID.Length + depth));
foreach (var child in node)
{
BuildString(sb, child, depth + 1);
}
}
Usage:
var tree = TreeNode.BuildTree(#"
Cat1
Sub1
Item1
Item2
Item3
Sub2
Item1
Item2
Cat2
Sub1
Sub2
Item1
Item2
Sub3
Item1
Cat3
Cat4");

I created a Node class that could be helpfull. It is fast and has some extra properties, like:
Ancestors
Descendants
Siblings
Level of the node
Parent
Root
Etc.

You can write a simple binary tree , I wrote some Pseudo code beloew:
class TreeNode {
TreeNode Right;
TreeNode Left;
int id;
//...
}
class BinTree {
void Insert(TreeNode node)
{
while(true) {
if(node.id > target.id) {
if(target.Right != null) {
target = target.Right;
continue;
}
else {
target.Right = node;
break;
}
}
else if(node.id < target.id) {
if(target.Left != null) {
target = target.Left;
continue;
}
else {
target.Left = node;
break;
}
}
else {
throw new ArgumentException("Duplicated id");
}
}
}
TreeNode Search(int id)
{
TreeNode target = root;
while(target != null) {
if(id > target.id) {
target = target.Right;
}
else if(id < target.id) {
target = target.Left;
}
else {
return target;
}
}
return null;
}
}
But if your data count is very large, maybe AVL tree is more efficient

Related

FInd Previous nodes in a Tree in C#

I am trying to write a Function Previous(), to get the previous nodes of a Tree. The statement is: "We have a tree that is built using the class Node where an instance of the class represents a node in the tree. For simplicity, the node has a single data field of type int.
Your task is to write the extension method NodeExtensions.Previous() to find the previous element in the tree. You can write as many helper methods as you want, but don't change the signature of the extension method NodeExtensions.Previous()."
The node class goes like this:
public class Node
{
private List<Node> _children;
public Node(int data, params Node[] nodes)
{
Data = data;
AddRange(nodes);
}
public Node Parent { get; set; }
public IEnumerable<Node> Children
{
get
{
return _children != null
? _children
: Enumerable.Empty<Node>();
}
}
public int Data { get; private set; }
public void Add(Node node)
{
Debug.Assert(node.Parent == null);
if (_children == null)
{
_children = new List<Node>();
}
_children.Add(node);
node.Parent = this;
}
public void AddRange(IEnumerable<Node> nodes)
{
foreach (var node in nodes)
{
Add(node);
}
}
public override string ToString()
{
return Data.ToString();
}
}
I need to write an extension method like this:
using System;
using System.Linq;
public static class NodeExtensions
{
public static Node Previous(this Node node)
{
// TODO Implement extension method here
}
}
I have a test case:
using System;
using System.Text;
using NUnit.Framework;
public class NodeExtensionsTests
{
[Test]
public void Test()
{
// Test tree:
//
// 1
// +-2
// +-3
// +-4
// +-5
// +-6
// +-7
//
var lastNode = new Node(7);
var tree = new Node(
1,
new Node(
2,
new Node(3),
new Node(4)),
new Node(
5,
new Node(6),
lastNode));
// Expected output:
//
// 7
// 6
// 5
// 4
// 3
// 2
// 1
//
var n = lastNode;
while (n != null)
{
Console.WriteLine(n.Data);
n = n.Previous();
}
// Test
//
n = lastNode;
Assert.AreEqual(7, n.Data);
n = n.Previous();
Assert.AreEqual(6, n.Data);
n = n.Previous();
Assert.AreEqual(5, n.Data);
n = n.Previous();
Assert.AreEqual(4, n.Data);
n = n.Previous();
Assert.AreEqual(3, n.Data);
n = n.Previous();
Assert.AreEqual(2, n.Data);
n = n.Previous();
Assert.AreEqual(1, n.Data);
n = n.Previous();
Assert.IsNull(n);
}
}
Whatever I try, it either goes into an infinite loop, or just returns the root nodes instead of "all silblings". Can someone help me here?
I think this will work for you
public static class NodeExtensions
{
public static Node Previous(this Node node)
{
if (node.Parent == null) { return null; }
var brothers = (List<Node>) node.Parent.Children;
var index = brothers.IndexOf(node);
if(index == 0)
{
return node.Parent;
}
else
{
var next = brothers[index - 1];
while (next.Children.Any())
{
next = next.Children.Last();
}
return next;
}
}
}

Printing Tree and skipping certain values

here i have the following code and input that prints a tree structure. My question is how can i make it so that the nodes and leafs that have the value "Unavailable" are skipped from being printed.
namespace Tree{public class TreeNode<T>
{
private T value;
private bool hasParent;
private List<TreeNode<T>> children;
public TreeNode(T value)
{
if (value == null)
{
throw new ArgumentNullException("Cannot insert null value");
}
this.value = value;
this.children = new List<TreeNode<T>>();
}
public T Value
{
get
{
return this.value;
}
set
{
this.value = value;
}
}
public int ChildrenCount
{
get
{
return this.children.Count;
}
}
public void AddChild(TreeNode<T> child)
{
if (child == null)
{
throw new ArgumentNullException("Cannot insert null value");
}
if (child.hasParent)
{
throw new ArgumentException("The node already has a parent");
}
child.hasParent = true;
this.children.Add(child);
}
public TreeNode<T> GetChild(int index)
{
return this.children[index];
}
}
public class Tree<T>
{
private TreeNode<T> root;
public Tree(T value)
{
if (value == null)
{
throw new ArgumentNullException("Cannot insert null value");
}
this.root = new TreeNode<T>(value);
}
public Tree(T value, params Tree<T>[] children) : this(value)
{
foreach (Tree<T> child in children)
{
this.root.AddChild(child.root);
}
}
public TreeNode<T> Root
{
get
{
return this.root;
}
}
private void PrintDFS(TreeNode<T> root, string spaces)
{
if (this.root == null)
{
return;
}
Console.WriteLine(spaces + root.Value);
TreeNode<T> child = null;
for (int i = 0; i < root.ChildrenCount; i++)
{
child = root.GetChild(i);
PrintDFS(child, spaces + " ");
}
}
public void TraverseDFS()
{
this.PrintDFS(this.root, string.Empty);
}
}
public static class TreeExample
{
static void Main()
{
Tree<string> tree =
new Tree<string>("John",
new Tree<string>("Jasmine",
new Tree<string>("Jay"),
new Tree<string>("Unavailable")),
new Tree<string>("Unavailable",
new Tree<string>("Jack"),
new Tree<string>("Jeremy")),
new Tree<string>("Johanna")
);
tree.TraverseDFS();
}
}}
right now it prints :(John, (Jasmine, (Jay), (Unavailable)), (Unavailable, (Jack, (Jeremy))), (Johanna))
I need it to print :(John, (Jasmine, (Jay)), (Johanna))
So basically skip every leaf with the value "Unavailable" and every node with the value "Unavailable" and all children from that node
Thanks !
This should work:
private void PrintDFS(TreeNode<T> root, string spaces)
{
if (this.root == null
|| "Unavailable" == root.Value.ToString())
{
return;
}
...
The accepted answer is a literally correct answer to the question, but it bakes in logic about what to do with the tree into the tree itself. A tree is a kind of collection or data structure, and you don't often see a List or Dictionary that is able to print itself. Instead the collection provides the right methods to get or change its contents so that you can do what you want.
In your case, you could do something like the following:
public enum TreeVisitorResult {
SkipNode,
Continue
}
// the following two methods inside Tree<T>:
public void VisitNodes(Func<TreeNode<T>, int, TreeVisitorResult> visitor) {
VisitNodes(0, this.root, visitor);
}
private void VisitNodes(int depth, TreeNode<T> node,
Func<TreeNode<T>, int, TreeVisitorResult> visitor) {
if (node == null) {
return;
}
var shouldSkip = visitor(node, depth);
if (shouldSkip == TreeVisitorResult.SkipNode) {
return;
}
TreeNode<T> child = null;
for (int i = 0; i < node.ChildrenCount; i++) {
child = node.GetChild(i);
VisitNodes(depth + 1, child, visitor);
}
}
If you had this method, you could write the Print method outside of the Tree classes, as:
tree.VisitNodes((treeNode, depth) => { // <- this lambda will be called for every node
if (treeNode.Value == "Unavailable") { // <- no need to ToString or cast here, since
// we know that T is string here
return TreeVisitorResult.SkipNode;
} else {
var spaces = new string(' ', depth * 3);
Console.WriteLine(spaces + treeNode.Value);
}
});

Need help to figure out the error in this search program

I have this linked list c# codes. I couldn't figure out the error for not printing any output. I have an error message saying that LinkedList.LinkedList doesn't contain a definition for PrintNodes. Can anyone pointed out why I am getting that error, and where I am doing mistake.
public class Node
{
public object data;
public Node next;
public Node(object data)
{
this.data = data;
}
}
public class LinkedList
{
Node head;
Node current;
public Node Head
{
get { return head; }
}
public void Add(Node n)
{
if (head == null)
{
head = n;
current = head;
}
else
{
current.next = n;
current = current.next;
}
}
public void MergeSortedList(Node first, Node second)
{
if (Convert.ToInt32(first.next.data.ToString())
> Convert.ToInt32(second.data.ToString()))
{
Node t = first;
first = second;
second = t;
}
head = first;
while ((first.next != null) && (second != null))
{
if (Convert.ToInt32(first.next.data.ToString())
< Convert.ToInt32(second.data.ToString()))
{
first = first.next;
}
else
{
Node n = first.next;
Node t = second.next;
first.next = second;
second.next = n;
first = first.next;
second = t;
}
}
if (first.next == null)
first.next = second;
}
static void Main()
{
LinkedList l1 = new LinkedList();
l1.Add(new Node("2"));
l1.Add(new Node("3"));
l1.Add(new Node("4"));
l1.Add(new Node("5"));
l1.Add(new Node("8"));
l1.Add(new Node("100"));
l1.Add(new Node("120"));
LinkedList l2 = new LinkedList();
l2.Add(new Node("10"));
l2.Add(new Node("30"));
l2.Add(new Node("34"));
LinkedList list = new LinkedList();
list.MergeSortedList(l1.Head, l2.Head);
list.PrintNodes();
Console.ReadLine();
}
}
}
In Main you call list.PrintNodes() but your LinkedList class has no such method defined, hence the exception, exactly as it says so:
LinkedList.LinkedList doesn't contain a definition for PrintNodes

Build tree data from dictionary

I have structure as below
{
"Start": "CDG",
"AirportsRoutes":
{
"BKK" : ["SIN", "DXB", "CDG", "SFO"],
"CDG" : ["LHR", "SIN"],
"JFK" : ["CDG", "DXB"],
"JNB" : ["SIN"],
"SIN" : ["SFO", "BKK"],
"SFO" : ["JFK", "BKK", "LHR"],
"LHR" : ["CDG", "JFK", "DXB"],
"YYZ" : ["SFO", "JFK"],
"DXB" : ["JNB", "SIN", "BKK"]
}
}
I created dictionary for AirportsRoutes as Dictionary<string, List<string>>.
I would like to build tree of data from this dictionary by using value to be next node for example if use "CDG" for root node.
Each leaf node will be stop if found the same key of their parent node.
CDG->LHR->CDG
->LHR->JFK->CDG
->LHR->JFK->DXB->JNB->SIN->SFO->JFK
->LHR->JFK->DXB->JNB->SIN->SFO->BKK
->LHR->JFK->DXB->JNB->SIN->SFO->LHR
->LHR->JFK->DXB->JNB->SIN->BKK...
->LHR->JFK->DXB->SIN->SFO...
->LHR->JFK->DXB->SIN->BKK..
->LHR->JFK->DXB->BKK..
->LHR->DXB..
Does everyone know how to make it or do I need to change Dictionary to something else ?
This little console app does what you want:
public class Program
{
public class TreeNode<T>
{
public List<TreeNode<T>> children = new List<TreeNode<T>>();
public T thisItem;
public TreeNode<T> parent;
}
public static void Main(string[] args)
{
var dict = new Dictionary<string, List<string>>
{
{"BKK", new List<string>{"SIN", "DXB", "CDG", "SFO"}},
{"CDG" , new List<string>{"LHR", "SIN"}},
{"JFK" , new List<string>{"CDG", "DXB"}},
{"JNB" , new List<string>{"SIN"}},
{"SIN" , new List<string>{"SFO", "BKK"}},
{"SFO" , new List<string>{"JFK", "BKK", "LHR"}},
{"LHR" , new List<string>{"CDG", "JFK", "DXB"}},
{"YYZ" , new List<string>{"SFO", "JFK"}},
{"DXB", new List<string> {"JNB", "SIN", "BKK"}}
};
var tree = BuildTree(dict, "CDG");
}
public static TreeNode<T> BuildTree<T>(Dictionary<T, List<T>> dictionary, T root)
{
var newTree = new TreeNode<T>
{
thisItem = root,
};
newTree.children = GetChildNodes(dictionary, newTree);
return newTree;
}
public static List<TreeNode<T>> GetChildNodes<T>(Dictionary<T, List<T>> dictionary, TreeNode<T> parent)
{
var nodeList = new List<TreeNode<T>>();
if (dictionary.ContainsKey(parent.thisItem))
{
foreach (var item in dictionary[parent.thisItem])
{
var nodeToAdd = new TreeNode<T>
{
thisItem = item,
parent = parent,
};
if (!ContainedInParent(parent, item))
{
nodeToAdd.children = GetChildNodes(dictionary, nodeToAdd);
}
// output leaf node for debugging!
if (nodeToAdd.children.Count == 0)
{
Console.WriteLine(NodeString(nodeToAdd));
}
nodeList.Add(nodeToAdd);
}
}
return nodeList;
}
private static string NodeString<T>(TreeNode<T> node)
{
return (node.parent != null ? NodeString(node.parent) + "->" : string.Empty) + node.thisItem;
}
private static bool ContainedInParent<T>(TreeNode<T> parent, T item)
{
var found = false;
if (parent != null)
{
if (parent.thisItem.Equals(item))
{
found = true;
}
else
{
found = ContainedInParent(parent.parent, item);
}
}
return found;
}
}
The output is:
CDG->LHR->CDG
CDG->LHR->JFK->CDG
CDG->LHR->JFK->DXB->JNB->SIN->SFO->JFK
CDG->LHR->JFK->DXB->JNB->SIN->SFO->BKK->SIN
CDG->LHR->JFK->DXB->JNB->SIN->SFO->BKK->DXB
CDG->LHR->JFK->DXB->JNB->SIN->SFO->BKK->CDG
.........

How to clone a whole tree without affecting the original one?

i use the solution in this link not work
Deep cloning objects
the following code, can not copy to a new tree, mutate will affect the original tree root(root)
foreach (Bag b in bag_list)
{
if (b.cards.Count() == 2)
{
Node original_root = new Node();
original_root = (Node)root.Clone(); // copy to a new tree
target_list = choose_valid_target(target_list, b.cards, b.cards.Count() - 1);
foreach (Target t in target_list)
{
Console.WriteLine("op:" + t.op + ", label:" + t.label);
Node mutated_root = mutate(original_root, target_list);
result = "";
result = inorder(mutated_root, result); // get inorder
Console.WriteLine(result.Substring(1, result.Length - 2)); //print
}
}
}
public class Node : System.Object, ICloneable
{
public int priority;
/*
7 alphabet
6 (,)
5 *,/,%
4 +,-
3 <,<=,>,>=
2 &&,||
1 =
*/
public string Data;
public Node Left;
public Node Right;
public string Label;
public object Clone()
{
//return this as object;
return this.MemberwiseClone();
//return new Node() as object;
}
}
public Node mutate(Node root, List<Target> targets) // mutate
{
if (root != null)
{
if (!IsLeaf(root.Left.Data))
mutate(root.Left, targets);
foreach (Target target in targets)
{
if (root.Label == target.label)
{
root.Data = target.op;
}
}
if (!IsLeaf(root.Right.Data))
mutate(root.Right, targets);
}
return root;
}
Clone all nodes recursively:
public object Clone()
{
Node clone = (Node)MemberwiseClone();
if (Left != null)
clone.Left = (Node)Left.Clone();
if (Right != null)
clone.Right = (Node)Right.Clone();
return clone;
}

Categories