C# Cannot Link nodes in a LinkedList - c#

I am extending the C# double linked list as a means of creating a custom data structure for a rule engine algorithm I am working on. Unfortunately, the elements in the linked list after instantiation are never actually linked:
public abstract class DependencyTree<TTreeLeaf,TTreeLeafNode>
: LinkedList<LinkedListNode<TTreeLeaf>>
where TTreeLeaf : DependencyTreeLeaf
where TTreeLeafNode : DependencyTreeLeafNode
{
#region Constructors
public DependencyTree(ICollection<TTreeLeaf> leaves)
{
foreach (var leaf in leaves)
{
AddLast(new LinkedListNode<TTreeLeaf>(leaf));
}
var y = this.Where(node => node.Next != null || node.Previous != null).Count();
Console.WriteLine(y.ToString());
}
#endregion Constructors
The above always returns 0, no matter how many Leaves I pass in.
What is the correct way to insure that my leaves are actually linked? I'd rather not roll yet another custom data structure when .NET already has it available. Any tips are much appreciated.
*****EDIT*****
//Addition of DependencyLeaf definition
public abstract class DependencyTreeLeaf
: LinkedList<LinkedListNode<DependencyTreeLeafNode>>
{
#region Constructors
public DependencyTreeLeaf(IEnumerable<DependencyTreeLeafNode> leafNodes, DependencyState siblingDependency = DependencyState.Unset, IEnumerable<DependencyTreeLeaf> children = null, DependencyState childDependency = DependencyState.Unset)
{
foreach (var leaf in leafNodes)
{
AddLast(new LinkedListNode<DependencyTreeLeafNode>(leaf));
}
if (children != null)
{
Children = new LinkedList<LinkedListNode<DependencyTreeLeaf>>();
foreach (var childLeaf in children)
{
Children.AddLast(new LinkedListNode<DependencyTreeLeaf>(childLeaf));
}
}
SiblingForwardDependency = siblingDependency;
ChildDownwardDependency = childDependency;
}
}

you are adding your own linkedlist nodes, you don't need to do this, the linked list will do this. You are adding those LinkedListNodes into the actual LinkedListNodes, hence, your ones don't have any previous or next being maintained. However, the problem you are facing is the IEnumerable will iterate over TTreeLeaf and not nodes.
If you want to iterate over the Nodes themselves then you need something like :-
public class DependencyTree<TTreeLeaf, TTreeLeafNode>
: LinkedList<TTreeLeaf>
where TTreeLeaf : DependencyTreeLeaf
where TTreeLeafNode : DependencyTreeLeafNode
{
public DependencyTree(ICollection<TTreeLeaf> leaves)
{
foreach (var leaf in leaves)
{
AddLast(leaf);
}
var y = this.Nodes().Count(node => node.Next != null || node.Previous != null);
Console.WriteLine(y.ToString());
}
public IEnumerable<LinkedListNode<TTreeLeaf>> Nodes()
{
var node = this.First;
while (node != null)
{
yield return node;
node = node.Next;
}
}
}
you can of course just go this.Count();

Related

singly linked list in c# using extension method

why extension method does not return the modified node in Insertion operations.
But It Working Fine at the time of Linked list Creation.
Extension method should return the modified Node.
What is the perfect way to do this.
IS extension method good in performance
Code follows
public class Node
{
public Object Data { get; set; }
public Node NextNode { get; set; }
}
public static class ListOperations
{
public static void CreateLinkedList(this Node node, Object data)
{
if (node.Data == null)
{
node.Data = data;
}
else
{
Node newnode = new Node();
newnode.Data = data;
Node current = new Node();
current = node;
while (current.NextNode != null)
{
current = current.NextNode;
}
current.NextNode = newnode;
node = current;
}
}
public static void InsertNode(this Node node1, Object data, int position)
{
Node newnode = new Node();
newnode.Data = data;
if (position == 1)
{
newnode.NextNode = node1;
node1 = newnode;
}
}
}
class Program
{
static void Main(string[] args)
{
Node node = new Node();
//random Singly LinkedList
node.CreateLinkedList(10);
node.CreateLinkedList(11);
node.CreateLinkedList(12);
node.CreateLinkedList(13);
node.CreateLinkedList(14);
node.CreateLinkedList(15);
node.InsertNode(20, 1);// this method does not return node value what is inserted.
}
}
There are many things wrong with your code, and we can deal with them later. But let's answer your questions first. I will be a bit literal and direct, since I can't assume why you have done it the way it is done.
why extension method does not return the modified node in Insertion operations.
Since your method doesn't return anything
But It Working Fine at the time of Linked list Creation.
Yes, since that code doesn't ever modify the this Node node parameter
Extension method should return the modified Node.
Only if you actually return any data from the method!
What is the perfect way to do this.
See below
IS extension method good in performance
Extension method compared with what? Compared with member method written similarly, there should really be no performance difference in the cases relevant to your example
Perfect way to do it:
So first things first: There is no need to write an extension method here. Why wouldn't you write a regular member method? Extensions are usually done when the class you want to add the functionality is not directly available for you to edit, typically as the code belongs to a third party
Second, you don't quite seem to understand the references and how the pass-by-value works. First let me post a better code, and then explain it
public class Node {
public object Data { get; set; }
public Node NextNode { get; set; }
public Node(object data) {
Data = data;
}
public Node AppendNode(object data) {
var newNode = new Node(data);
var current = this;
while (current.NextNode != null)
current = current.NextNode;
current.NextNode = newNode;
return newNode;
}
public Node SetFirstNode(object data) {
return new Node(data) { NextNode = this };
}
}
class Program {
static void Main(string[] args) {
var linkedList = new Node(10);
linkedList.AppendNode(11);
linkedList.AppendNode(12);
linkedList.AppendNode(13);
linkedList.AppendNode(14);
linkedList.AppendNode(15);
linkedList = linkedList.SetFirstNode(20);
}
}
The important things to notice from the perspective of your main question (why the insert did not work) is that the method SetFirstNode actually returns the newly created node and in Main, we re-assign the linkedlist as such linkedList = linkedList.SetFirstNode(20);
Now, you can actually write a static method and pass by ref the linkedlist, but that is not a good practice, in my opinion. Nevertheless, the code would look like below
public static class ListOperations {
public static void InsertNode(ref Node linkedList, object data) {
linkedList = new Node(data) { NextNode = linkedList };
}
}
Among other things to notice, I am calling the node object as linkedList, CreateLinkedList as AppendNode and InsertNode as SetFirstNode on purpose, so you can understand the code better.
Below is the same code with generic argument instead of object Data and using a proper InsertNode method
public class Node<T> {
public T Data { get; set; }
public Node<T> Next { get; set; }
public override string ToString() {
return Data.ToString();
}
public Node(T data) {
Data = data;
}
public Node<T> AppendNode(T data) {
var newNode = new Node<T>(data);
var current = this;
while (current.Next != null)
current = current.Next;
current.Next = newNode;
return newNode;
}
/// <summary>
/// Inserts a new node into the linkedlist as the desired position
/// </summary>
/// <param name="position">0-based index for the final position of new node</param>
/// <param name="newNode">The newly created node containing data</param>
/// <returns>returns the first node of the linkedlist</returns>
public Node<T> InsertNode(T data, int position, out Node<T> newNode) {
var current = this;
position--;
newNode = new Node<T>(data);
if (position < 0) {
newNode.Next = current;
return newNode;
}
for (int i = 0; i < position; ++i)
current = current.Next;
newNode.Next = current.Next;
current.Next = newNode;
return this;
}
}
class Program {
static void Main(string[] args) {
var linkedList = new Node<int>(10);
linkedList.AppendNode(11);
linkedList.AppendNode(12);
linkedList.AppendNode(13);
linkedList.AppendNode(14);
linkedList.AppendNode(15);
linkedList = linkedList.InsertNode(20, 0, out var newNode);
}
}

How to handle parameters right in c#?

I just started using c# again and now I have a strange problem with my parameters.
I tried to build a List by my self.
So I have:
class NodeList
{
public Node FirstCity { get; set; }
public Node findNode(String name)
{
//...stuff
}
}
And This:
class Node
{
public String Name {get; set;}
public Node next {get; set;}
}
So, in my project I (lets say on button click) create a new Nodelist.
(By default I have already a few nodes in it.)
Now I do this:
Node n = nodelist.findNode("test");
and then I have another class I called tool.
tool.doSomething(n , nodelist);
Now the strange thing is that, when I look at nodelist, when I call the above the list is correct. The doSomething method, doesn´t even call the nodelist but it changes it.
doSomething(n, list)
{
NodeList nl = new NodeList();
nl.Add(n);
//other stuff
}
At the point where I change the new List for some reason the other list, which is in a different class, changes too.
Can anyone please explain why and how I can fix this!?
Edit:
This is my Add Method:
Add(Node node){
node.next = null;
Node current = FirstCity;
if (current == null)
FirstCity = node;
else
{
while (current.next != null)
{
current = current.next;
}
current.next = node;
}
}

Populating a TreeView from a Tree<T> object

I need to show a Tree<T> hierarchy in a TreeView, differentiating between the tree nodes and the tree leaves.
The Tree object is constructed at run time and there is no knowledge of its depth. Not a binary tree.
This is the DataTree class:
public class TreeNode<T> : IEnumerable<TreeNode<T>>
{
public T Data { get; set; }
public TreeNode<T> Parent {get; set;}
public ICollection<TreeNode<T>> Children {get; set;}
.....
.....
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<TreeNode<T>> GetEnumerator()
{
yield return this;
foreach (var directChild in this.Children)
{
foreach (var anyChild in directChild)
yield return anyChild;
}
}
}
And this is the code to populate the TreeView:
public void CreateTreeView()
{
AttributesTreeView=new TreeView();
foreach(TreeNode<string> entry in NewAttTree)
{
if(entry.Children.Count>0)
{
int tn=AttributesTreeView.Nodes.Add(new TreeNode(entry.Data.ToString().Replace("|",string.Empty)));
foreach(TreeNode<string> str in entry.Children)
{
if(tn!=0)
{
int itn=AttributesTreeView.Nodes[tn].Nodes.Add(new TreeNode(str.Data.ToString()));
}
}
}
}
}
What you're doing here is taking one tree, and projecting each node in that tree into something else, while maintaining the structure of that tree. This is actually fairly simple. Simply create a lookup that maps each node to all of its children, and then go through each of your nodes, look up "yourself" and then add all of the children from the lookup to your new node:
var roots = new TreeNode<string>[] { }; //the original data to map
var lookup = roots.SelectMany(node => node)
.ToLookup(node => node.Parent, node => new
{
node,
UINode = new TreeNode(node.Data),
});
foreach (var pair in lookup.SelectMany(group => group))
foreach (var child in lookup[pair.node])
pair.UINode.Nodes.Add(child.UINode);
TreeView view = new TreeView();
foreach (var root in lookup[null]) //assume nodes with a null parent are roots
view.Nodes.Add(root.UINode);
I can think of three ways to load a subset of the DataTreeNode structure:
Filtering: create a new DataTreeNode structure from the old structure, excluding subtrees that contain unwanted leaf nodes. Load the result.
Add a property to DataTreeNode that represents the range of values in its subtrees' leaf nodes, like a Huffman tree. Then on load, check the property before adding a given DataTreeNode.
For each DataTreeNode create a TreeNode, but discard the TreeNode if its subtrees' leaf nodes don't match the required values.
Below is pseudocode for option 3, using a HashSet to look up the required leaf node values.
void LoadDataTreeNode(TreeView treeView, DataTreeNode<T> dataTreeNode, HashSet<T> hashSet)
{
treeView.Nodes.Clear();
LoadDataTreeNode(treeView.Nodes, dataTreeNode, hashSet);
}
bool LoadDataTreeNode(TreeNodeCollection treeNodes, DataTreeNode<T> dataTreeNode, HashSet<T> hashSet)
{
bool result = hashSet.Contains(dataTreeNode.Data);
if (result)
{
var treeNode = new TreeNode(dataTreeNode.Data.ToString());
// Use this treeNode if at least one of its subtrees contains
// the required leaf node values. Assume that all other
// subtrees will be discarded by the relevant recursive calls.
result = false;
foreach (var child in dataTreeNode.Children)
{
if (LoadDataTreeNode(treeNode.Nodes, child, hashSet))
{
result = true;
}
}
if (result)
{
treeNodes.Add(treeNode);
}
}
return result;
}
OK, got it.
TreeNode newNode=new TreeNode("SEARCH");
AttributesTreeView.Nodes.Add(newNode);
CreateTreeView(NewAttTree,newNode);
public void CreateTreeView(DataTreeNode<string> root, TreeNode parentNode)
{
foreach(DataTreeNode<string> node in root.Children)
{
try
{
TreeNode newNode=new TreeNode(node.Data.ToString());
parentNode.Nodes.Add(newNode);
CreateTreeView(node,newNode);
}
catch (System.Exception e)
{
}
}
#groverboy: thanks for the push in the right direction.
One more question which presents itself:
How can we scan the DataTree structure and populate the TreeView only with the nodes that have leaves of certain value[s]. I mean in a DFT traversal, how can we decide to add a node before visiting the leaves and deciding if and which fit the filter criteria?
#groverboy: I tried your method but it didn't work and I noticed it won't ever get past the first if clause, unless the root DataTreeNode fits the bill, otherwise it returns without iterating the data tree at all.
Here is the method I came up with, based on your code: it works, but adds the same branch multiple times and I must be blind but I cant see why; maybe another pair of eyes.
bool PopulateTreeNode(DataTreeNode<string> dataNode,TreeNode treeNodes,string filter,bool ignoreCase)
{
if(dataNode.IsLeaf)
{
if(WcMatchExtensionMethods.WcMatches(dataNode.Data,filter,ignoreCase))
{
treeNodes.Nodes.Add(new TreeNode(dataNode.Data.ToString()));
return true;
}
else
return false;
}
bool result = false;
TreeNode treeNode=new TreeNode(dataNode.Data.ToString());
foreach (DataTreeNode<string> child in dataNode.Children)
{
if(PopulateTreeNode(child,treeNode,filter,ignoreCase))
{
treeNodes.Nodes.Add(treeNode);
result = true;
}
}
return result;
}

Foreach loop on a generic list in a class which inherits from a abstract class

(The title is not very good I supposed... feel free to change; I hope I can express myself better with an example)
I have the following classes:
abstract class AbstractObject<T>
{
List<T> Children { get; protected set; }
}
class A : AbstractObject<A>
{
//I have access to a List<A>
}
class B : AbstractObject<B>
{
//I have access to a List<B>
}
Then, at some point I have the following method:
private TreeNode PupulateRecursively<T>(AbstractObject<T> _us)
{
if (_us.Children == null || _us.Children.Count == 0)
{
return new TreeNode(string.Format("{0} - {1}", _us.FormattedID, _us.Name)) { Tag = _us };
}
else
{
Debug.Assert(_us.Children.Count > 0);
TreeNode node = new TreeNode(string.Format("{0} - {1}", _us.FormattedID, _us.Name)) { Tag = _us };
foreach (var child in _us.Children)
{
TreeNode n = PupulateRecursively(child);
node.Nodes.Add(n);
}
return node;
}
}
But I'm getting a: The type arguments for method PupulateRecursively<T> (AbstractRallyObject<T>) cannot be inferred from the usage. Try specifying the type arguments explicitly., because the child var inside the foreach is of type T.
How can I fix this? It is a design issue?
The parameter to PupulateRecursively<T> is an AbstractRallyObject<T> but you're passing in a T:
foreach (var child in _us.Children) // Children is a List<T>
{
TreeNode n = PupulateRecursively(child); //child is a T
you could define Children as a List<AbstractObject<T>> whichi would compile but I don't know enough about your design to know if it's right.
It seems you call your PupulateRecursively method without the generic argument like this :
TreeNode n = PupulateRecursively<T>(child);
It looks like you need to define your collection as List<AbstractObject<T>>
abstract class AbstractObject<T>
{
List<AbstractObject<T>> Children { get; protected set; }
}

Filling up a TreeView control

I have a N-Ary non sorted in any way tree and each node can have 0-N children. Given the data structure below, how can I fill the tree view assuming you have an array of TermNodes and that array is the first level of the TreeView? I have not been able to come up with a recursive way to do this.
class TermNode
{
public string Name;
public string Definition;
public List<TermNode> Children
}
Here is a bit of code to get you started with the recursion. It's not tested (I can't right now), but you should get the idea:
public static void BuildTreeView(TreeNodeCollection Parent, List<TermNode> TermNodeList)
{
foreach (TermNode n in TermNodeList)
{
TreeNode CurrentNode = Parent.Add(n.Name);
// no need to recurse on empty list
if (n.List.Count > 0) BuildTreeView(CurrentNode.Nodes, n.List);
}
}
// initial call
List<TermNode> AllTermNodes = /* all your nodes at root level */;
BuildTreeView(treeView1.Nodes, AllTermNodes);
Just took out Generics for a spin.. Worked nicely. Worth a look at...
public interface INode<T>
{
List<T> Children { get; }
}
class TermNode:INode<TermNode>
{
public string Name;
public string Definition;
public List<TermNode> Children { get; set; }
public TermNode()
{
this.Children = new List<TermNode>();
}
}
public class TreeBuilder<T> where T : INode<T>
{
public Func<T, TreeNode> obCreateNodeFunc;
public void AddNode(TreeView obTreeView, T obNodeToAdd, TreeNode obParentNodeIfAny)
{
TreeNodeCollection obNodes;
if (obParentNodeIfAny == null)
{
obNodes = obTreeView.Nodes;
}
else
{
obNodes = obParentNodeIfAny.Nodes;
}
int iNewNodeIndex = obNodes.Add(obCreateNodeFunc(obNodeToAdd));
TreeNode obNewNode = obNodes[iNewNodeIndex];
foreach (T child in obNodeToAdd.Children)
{
AddNode(obTreeView, child, obNewNode);
}
}
}
// calling code - Some class
static TreeNode GetTreeNodeFor(TermNode t)
{
return new TreeNode(t.Name); // or any logic that returns corr TreeNode for T
}
void Main()...
{
TermNode[] arrNodesList;
// populate list with nodes
TreeBuilder<TermNode> tb = new TreeBuilder<TermNode>();
tb.obCreateNodeFunc = GetTreeNodeFor;
foreach (TermNode obNode in arrNodesList)
{
tb.AddNode(treeView, obNode, null);
}
}
Thanks All I was getting confused because I did not realize that for a given TreeNode tn, tn.Nodes.Add would return the added TreeNode
Once you know that the solution is straight forward like so
private void /*TreeNode*/ RecursiveAdd(OntologyNode on, TreeNode tn)
{
if (on.Children.Count == 0)
{
return;
}
foreach (OntologyNode child in on.Children)
{
TreeNode tCur = tn.Nodes.Add(child.Name);
tCur.Tag = child;//optional for some selected node events
RecursiveAdd(child, tCur);
}
}
and to start of the recursive call
foreach( OntologyNode on in Nodes )
{
if (on.IsTopLevelNode == true)// internal not pertinent to this code snippet
{
TreeNode tn = tvOntoBrowser.Nodes.Add(on.Name);
tn.Tag = on;
if (on.Children.Count > 0)
{
RecursiveAdd(on, tn);
}
}
}

Categories

Resources