DFS on C# custom data structure: find loops in a graph - c#

I need to implement a DFS on a undirected graph.
My data structure is simple.
I have a Node class and a Dictionary
It contains the neighbours (Node) of each node in the graph. So the keys are nodes and the values are their directly connected nodes.
How can I implement the DFS for counting the cycles in the graph?
This is my current code:
foreach (Node n in nodeList)
{
while (loopFounded == false)
{
visitNode(n);
if (loopFounded == true)
{
loops.Add(loopIndex, new ArrayList(visiting));
visiting.Clear();
loopIndex = loopIndex + 1;
}
}
loopFounded = false;
}
The visitNode function is:
void visitNode(Node n)
{
if (visiting.Capacity != 0 && visiting.Contains(n))
{
Console.WriteLine("loop!");
loopFounded = true;
return;
}
visiting.Add(n);
if (neighbours.ContainsKey(n))
{
foreach (Node node in neighbours[n])
{
if (!visited.Contains(node) && !visiting.Contains(node))
{
visitNode(node);
}
}
visited.Add(n);
}
return;
}
It is returning only loops composed by couples of nodes...
Can someone help me? Thanks

Related

How can I delete a node from a singly linked list?

I'm taking lines (I:3, I:6, D:5, etc) from a text file and splitting them on the colon. Then, taking the number after the colon and pushing it to a node in a linked list. Depending on the line, it will insert(I) or delete(D) the node. However, I'm having trouble deleting a node. I created a method called deleteNode()
I reference this method in my if statement to check whether or not the command in the file starts with I or D to be told whether it gets inserted or deleted or not. I'm having trouble on how to reference the node to be deleted in llist.deletenode();
public class LinkedList
{
Node head; // the head of list
public class Node
{
public int data;
public Node next;
// constructor
public Node(int d)
{
data = d;
next = null;
} // end of constructor
}
public void printList()
{
// traversing list and printing the contents starting from head(1)
Node n = head;
int count = 0;
while (n != null)
{
count++;
Console.Write("Node" + count + ":" + " " + n.data + " ");
n = n.next;
}
}
public void push(int new_data)
{
// ads node to list
Node new_node = new Node(new_data); //allocate new node, put in data
new_node.next = head; //make next of new node as head
head = new_node; //moving head to point to the new node
}
public static void deleteNode(Node node, Node n)
{
// deletes node from list
// find the previous node
Node prev = node;
while (prev.next != null && prev.next != n)
{
prev = prev.next;
}
// Check if node really exists in Linked List
if (prev.next == null)
{
Console.WriteLine("Given node is not" +
"present in Linked List");
return;
}
// Remove node from Linked List
prev.next = prev.next.next;
// Free memory
GC.Collect();
return;
}
}
// main method to create a linked list with 3 nodes
public static void Main(String[] args)
{
// starting with an empty list
LinkedList llist = new LinkedList();
string[] lines = File.ReadAllLines(#"C:\\Users\project\text.txt");
foreach (string line in lines)
{
// splitting the lines on the colon
string[] bits = line.Split(':');
// taking the bit after the colon and parsing
// into an integer - the i is already parsed
int x = int.Parse(bits[1]); //the value after colon
if (bits[0] == "i")
{
llist.push(x);
}
else if (bits[0] == "d")
{
deleteNode(llist, existingNode); //error here
}
}
llist.printList();
}
I think the logic should probably match that of the push method (not sure why push isn't called Add or Insert instead, though...), in that it should look for the first node whose data matches the data we want to delete.
If we start at the head, we first want to determine if the head should be deleted. If so, then we reset the head to head.next and we're done!
Otherwise, we examine head.Next to see if it's the one to delete. If it is, then we set head.Next equal to head.Next.Next, effectively removing head.Next from our list (no node is pointing to it anymore).
If head.Next is not the node to delete, then we move to the next node and continue the process.
Here's an example:
public void DeleteNode(int nodeData)
{
// First check if the head is the node to delete
if (head != null && head.data == nodeData)
{
// If it is, set the head to the next node (effectively removing it from the list)
head = head.next;
return;
}
// Start at the head node
var current = head;
while (current != null)
{
// Get the next node
var next = current.next;
// See if the next node is the one to delte
if (next != null && next.data == nodeData)
{
// It is, so set the current node's Next pointer to the *next* node's
// Next pointer (effectively removing the Next node from the list)
current.next = next.next;
return;
}
// Update our current node to the next one and keep looking
current = next;
}
}
There are a lot of issues with your code ranging from aesthetic (name casing), to syntax errors, to design errors (static functions instead of methods).
I am offering some cleanup and an example below. The result is
Print List:
Node1: 0 Node2: 1 Node3: 2 Node4: 3 Node5: 4 Node6: 5
Deleting 4
Print List:
Node1: 0 Node2: 1 Node3: 2 Node4: 3 Node5: 5
and the sample code. The main addition is a separate function that finds the previous node FindPrevious() and use the existing Head of the list in DeleteNode().
Also changed fields into properties and PascalCasing as recommended per C# design rules.
namespace ConsoleApp1
{
public class Node
{
public int Data { get; set; }
public Node Next { get; set; }
// constructor
public Node(int data)
: this(null, data)
{ }
// always add a full constructor
public Node(Node next, int data)
{
this.Data = data;
this.Next = next;
}
}
public class LinkedList
{
public Node Head { get; set; }
public string PrintList()
{
// traversing list and printing the contents starting from head(1)
Node n = Head;
int count = 0;
StringBuilder sb = new StringBuilder();
while (n != null)
{
count++;
sb.Append("Node" + count + ":" + " " + n.Data + " ");
n = n.Next;
}
return sb.ToString();
}
// adds node to list
public void Push(int data)
{
//allocate new node, put in data
//and make next of new node as head
//moving head to point to the new node
Head = new Node(Head, data);
}
public Node FindPrevious(Node node)
{
Node n = Head;
while (n!=null)
{
if (n.Next == node)
{
return n;
}
n = n.Next;
}
return null;
}
public void DeleteNode(Node node)
{
if (node==null)
{
return;
}
Node prev = FindPrevious(node);
if (prev!=null)
{
// skip over node
prev.Next = node.Next;
}
}
}
static class Program
{
static void Main(string[] args)
{
LinkedList llist = new LinkedList();
llist.Push(5);
llist.Push(4);
llist.Push(3);
llist.Push(2);
llist.Push(1);
llist.Push(0);
Console.WriteLine($"Print List:");
Console.WriteLine(llist.PrintList());
Console.WriteLine();
var existingNode = llist.Head.Next.Next.Next.Next;
Console.WriteLine($"Deleting {existingNode.Data}");
llist.DeleteNode(existingNode);
Console.WriteLine($"Print List:");
Console.WriteLine(llist.PrintList());
}
}
}
DeleteNode method takes in two arguments. You are using deleteNode as an extension method but it's a simple method with two inputs.
deleteNode(llist, nodeYouWantToDelete);
Also, your loop that checks for D isn't right
if (bits[0] == "i") { //loop that checks if command starts with i (for inserting)
llist.push(x);
} else if(bits[0] == "d") { // CHECK bits[0] not [1]
// Get the node that matches value
// check here if the node already exists then delete
deleteNode(llist, existingNode);
}
update
public void push(int new_data) { //ads node to list
Node new_node = new Node(new_data); //allocate new node, put in data
new_node.next = null; //next should always be null.
// start from head and find the node whose next = null, point that to new_node
}
public void deleteNode(Node nodeToDelete) { //deletes node from list
// start from head and keep going next until node.next = nodeToDelete
// set node.next = node.next.next;
}
Working Solution for you
public class LinkedList
{
Node head;
Node last;
public class Node
{
public int data;
public Node next;
public Node(int d)
{
data = d;
next = null;
} // end of constructor
}
public void print()
{
// traversing list and printing the contents starting from head(1)
Node n = head;
int count = 0;
while (n != null)
{
Console.Write("Node" + count++ + ":" + " " + n.data + " ");
n = n.next;
}
}
public void push(int new_data)
{
Node thisNode = new Node(new_data);
if (head == null)
{
head = thisNode;
last = head;
return;
}
last.next = thisNode;
last = last.next;
}
public void delete(Node node)
{
if (head.data == node.data)
head = head.next;
else
{
Node iterate = head;
bool deleted = false;
while (iterate.next != null)
{
if (iterate.next.data == node.data && !deleted)
{
iterate.next = iterate.next.next;
deleted = true;
continue;
}
iterate.next = iterate.next.next;
}
last = iterate;
if (!deleted)
{
Console.WriteLine("Given node is not " +
"present in Linked List");
}
// Free memory
GC.Collect();
return;
}
}
}
//and use it in the main like,
public static void Main(string[] args)
{
LinkedList llist = new LinkedList();
string[] lines = new[] { "i:1", "i:3", "d:3", "i:2", "i:1", "d:3" };
foreach(string line in lines)
{
string[] split = line.Split(':');
if (split[0] == "i") // INSERTS At the end of the list.
llist.push(int.Parse(split[1]));
else if (split[0] == "d") // Deletes the "FIRST" occurence of said number
llist.delete(new LinkedList.Node(int.Parse(split[1])));
}
Console.Read();
}

C# Delete node from BST - Am I on the right track?

EDIT:
Right thanks for helping earlier, I have been using and the step into and step over and it looks to be working but the nodes are not being deleted and I'm not sure why.
I actually use 5 arguments for the BST but just using the one for testing purposes. It compares and finds if it has any children no problem. Just wont set it to null.
only testing nodes with 0 or 1 children.
main
Tree aTree = new Tree();
aTree.InsertNode("a");
aTree.InsertNode("s");
aTree.InsertNode("3");
aTree.InsertNode("1");
aTree.InsertNode("p");
aTree.PreorderTraversal();
aTree.RemoveNode("p");
aTree.RemoveNode("3");
aTree.PreorderTraversal();
Console.ReadKey();
My Delete Methods are:
Tree Node
public void Remove(TreeNode root, TreeNode Delete) {
if (Data == null) {
}
if (Delete.Data.CompareTo(root.Data) < 0) {
root.nodeLeft.Remove(root.nodeLeft, Delete);
}
if (Delete.Data.CompareTo(root.Data) > 0) {
root.nodeRight.Remove(root.nodeRight, Delete);
}
if (Delete.Data == root.Data) {
//No child nodes
if (root.nodeLeft == null && root.nodeRight == null) {
root = null;
}
else if (root.nodeLeft == null)
{
TreeNode temp = root;
root = root.nodeRight;
root.nodeRight = null;
temp = null;
}
//No right child
else if (root.nodeRight == null)
{
TreeNode temp = root;
root = root.nodeLeft;
root.nodeLeft = null;
temp = null;
}
//Has both child nodes
else
{
TreeNode min = minvalue(root.nodeRight);
root.Data = min.Data;
root.nodeRight.Remove(root.nodeRight, min);
}
}
}
Find Min
public TreeNode minvalue(TreeNode node)
{
TreeNode current = node;
/* loop down to find the leftmost leaf */
while (current.nodeLeft != null)
{
current = current.nodeLeft;
}
return current;
}
Tree
public void RemoveNode(string Nation)
{
TreeNode Delete = new TreeNode(Nation);
root.Remove(root, Delete);
}
Remove is of return type void, but you're trying to assign it to root.nodeLeft and root.nodeRight, causing your type conversion error.
In general your Remove function needs to return the root of the sub-tree as the result, as in
public void Remove(TreeNode root, TreeNode Delete) {
if (Data == null) {
return null;
}
if (Delete.Data.CompareTo(root.Data) < 0) {
root.nodeLeft = (root.nodeLeft.Remove(root.nodeLeft, Delete));
return root;
}
... and so on.
Otherwise, since your nodes don't refer to their parents, there would be no way for the parent to know that the child node is gone, or that a new node is now at the root of the sub-tree.

Removing a node from a LinkedList (C#)

I created a LinkedList class with a function delete to remove a certain node from the list if found, however it's not working:
public class LinkedList
{
public Node head;
<...>
public void delete(string n)
{
Node x = search(n); //returns the node to delete or null if not found
if (x != null)
x = x.next;
}
<...>
}
I figured all I needed to do is find the node and set it to the next one (so the node is "removed" out of the linked list), however it's not. If anyone could help me out it'd be much appreciated!
EDIT: Forgot to mention I have a single linked list.
EDIT2: My new code:
public void delete(string n)
{
Node x = head;
while (x != null && x.name != n)
{
if (x.next.name == n)
x.next = x.next.next;
x = x.next;
}
if (x != null)
x = null;
}
You'll want to loop through the list until the next node is the one you want to delete. Then set the current to the next nodes next node.
public void Delete(string value)
{
if (head == null) return;
if (head.Value == value)
{
head = head.Next;
return;
}
var n = head;
while (n.Next != null)
{
if (n.Next.Value == value)
{
n.Next = n.Next.Next;
return;
}
n = n.Next;
}
}
This of course assumes you only want to delete the first match.

Recursively traversing a tree in C# from top down by row

Interesting problem posed by a friend recently: Imagine you've got a List< NodeType > of all nodes in a tree. How would you go about traversing down the tree from the root node, by row such that you find the first node with a specific value. So say that each node has 3 attributes: its name/location, the identity of its parent, and who "owns" the node. The problem is you want to find the highest node in the tree that you "own" no matter what branch its on. I understand the basic logic in so much as to find the first set of children you look for all nodes with a parent set as the first node. But how would you go about recursively search through a List<> of nodes to find the highest node you own?
You’re looking for breadth-first search. It is normally implemented using a queue:
public Node FindFirstByBreadthFirst(this Node node, Predicate<Node> match)
{
var queue = new Queue<Node>();
queue.Enqueue(tree.RootNode);
while (queue.Count > 0)
{
// Take the next node from the front of the queue
var node = queue.Dequeue();
// Process the node 'node'
if (match(node))
return node;
// Add the node’s children to the back of the queue
foreach (var child in node.Children)
queue.Enqueue(child);
}
// None of the nodes matched the specified predicate.
return null;
}
Algorithm:
Put the root node in a queue.
Repeat
Take item from queue;
Matching? return Item
Add all children to the queue
Until Queue is empty
Update: Haha, wow, this is completely wrong, I just realized (as in it is not doing what you asked for). Never mind -- looks like you already got a correct answer, anyway :)
I think I understand your problem. Let me know if I'm getting something wrong.
You have a NodeType class that looks something like this:
class NodeType
{
public string Name { get; }
public NodeType Parent { get; }
public int OwnderId { get; }
}
First order of business would be to write a function that takes a NodeType parameter and, given some enumerable collection of NodeType objects, returns all of its descendents in a recursive fashion:
IEnumerable<NodeType> GetNodeChildren(NodeType node, IEnumerable<NodeType> nodes)
{
var children = nodes.Where(n => n.Parent == node);
if (children.Any())
{
foreach (NodeType child in children)
{
yield return child;
var grandchildren = GetNodeChildren(child);
foreach (NodeType grandchild in grandchildren)
{
yield return grandchild;
}
}
}
}
Next up: write a function that takes a NodeType object and finds the highest descendent with a specified OwnerId. This is really a pretty simple operation, so I won't even define a proper function; I'll just use a lambda:
Func<NodeType, int, NodeType> findHighestDescendent = (node, id) => {
return GetNodeChildren(node).FirstOrDefault(child => child.OwnerId == id);
};
Now for any given Id value, it is quite trivial to find the highest matching NodeType:
int id = 10; // just for example
NodeType highestOwnedNode = nodes
.Select(n => findHighestDescendent(n, id))
.FirstOrDefault(n => (n != null));
public static Control FindChildControlByDepth(this Control Page, string ControlID, int depth)
{
if (depth > 10)
throw new ArgumentException("Cannot search beyond a depth of 10", "depth");
foreach (Control c in Page.Controls)
{
if (c.ID == ControlID)
return c;
if (depth > 0)
{
foreach (Control c1 in c.Controls)
{
if (c1.ID == ControlID)
return c1;
if (depth > 1)
{
foreach (Control c2 in c1.Controls)
{
if (c2.ID == ControlID)
return c2;
if (depth > 2)
{
foreach (Control c3 in c2.Controls)
{
if (c3.ID == ControlID)
return c3;
if (depth > 3)
{
foreach (Control c4 in c3.Controls)
{
if (c4.ID == ControlID)
return c4;
if (depth > 4)
{
foreach (Control c5 in c4.Controls)
{
if (c5.ID == ControlID)
return c5;
if (depth > 5)
{
foreach (Control c6 in c5.Controls)
{
if (c6.ID == ControlID)
return c6;
if (depth > 6)
{
foreach (Control c7 in c6.Controls)
{
if (c7.ID == ControlID)
return c7;
if (depth > 8)
{
foreach (Control c8 in c7.Controls)
{
if (c8.ID == ControlID)
return c8;
if (depth > 9)
{
foreach (Control c9 in c8.Controls)
{
if (c9.ID == ControlID)
return c9;
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
return null;
}

Merging Treenodes

Does anyone know of an algorithm that will merge treenodes in the following way?
treeA
\ child a
\node(abc)
\ child b
\node(xyz)
+
treeB
\ child a
\node(qrs)
\ child b
\node(xyz)
\node(pdq)
\ child c
\node(pdq)
= // do merge
treeMerged
\ child a
\node(abc)
\node(qrs)
\ child b
\node(xyz)
\node(pdq)
\ child c
\node(pdq)
Any help would be greatly appreciated.
Well, once I actually took the time to think about it, the solution turns out to be far more simple than I anticipated. (I've posted the critical part of the code below)
private TreeNode DoMerge(TreeNode source, TreeNode target) {
if (source == null || target == null) return null;
foreach (TreeNode n in source.Nodes) {
// see if there is a match in target
var match = FindNode(n, target.Nodes); // match paths
if (match == null) { // no match was found so add n to the target
target.Nodes.Add(n);
} else {
// a match was found so add the children of match
DoMerge(n, match);
}
}
return target;
}
Still interested to know if someone has a better solution?
Ok, I'll admit, when I first started messing with this, I didn't think it would be too hard, so I figured I'll try to do it using LINQ. It came out to be nuts, but it works. I'm SURE there are more elegant and efficient algorithms, but here it is!
First, I have a ToEnumerable extension method on the TreeNodeCollection class:
public static class TreeNodeCollectionExtensions
{
public static IEnumerable<TreeNode> ToEnumerable(this TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
yield return node;
}
}
}
Then, I implement a custom comparer:
public class TreeNodeComparer : IEqualityComparer
{
public bool Equals(TreeNode x, TreeNode y)
{
return x.Text == y.Text;
}
public int GetHashCode(TreeNode obj)
{
return obj.Text.GetHashCode();
}
}
And finally, the crazyness:
private TreeView MergeTreeViews(TreeView tv1, TreeView tv2)
{
var result = new TreeView();
foreach (TreeNode node in tv2.Nodes)
{
result.Nodes.Add(node.Clone() as TreeNode);
}
foreach (TreeNode node in tv1.Nodes)
{
var nodeOnOtherSide = result.Nodes.ToEnumerable()
.SingleOrDefault(tr => tr.Text == node.Text);
if (nodeOnOtherSide == null)
{
TreeNode clone = node.Clone() as TreeNode;
result.Nodes.Add(clone);
}
else
{
var n = node.Nodes.ToEnumerable()
.Where(t => !(nodeOnOtherSide.Nodes.ToEnumerable()
.Contains(t, new TreeNodeComparer())));
foreach (TreeNode subNode in n)
{
TreeNode clone = subNode.Clone() as TreeNode;
nodeOnOtherSide.Nodes.Add(clone);
}
}
}
return result;
}
The way I coded it was that it returns a third "merged" treeView. You can change the code, so that it takes a third treeview as a parameter, so that you can pass in a treeView you may already have.
Again, I'm SURE there are better way to do this, but it SHOULD work.
One more thing I'd like to point out, this will only work for a TreeView that is two layers deep.
I came up with this recursive example, works perfect in C# (have been using it myself), note that you'll need to find a way to convert TreeNode.Nodes to an array:
public static TreeNode[] mergeTrees(TreeNode[] target, TreeNode[] source)
{
if (source == null || source.Length == 0)
{
return target;
}
if (target == null || target.Length == 0)
{
return source;
}
bool found;
foreach (TreeNode s in source)
{
found = false;
foreach (TreeNode t in target)
{
if (s.Text.CompareTo(t.Text) == 0)
{
found = true;
TreeNode[] updatedNodes = mergeTrees(Util.treeView2Array(t.Nodes), Util.treeView2Array(s.Nodes));
t.Nodes.Clear();
t.Nodes.AddRange(updatedNodes);
break;
}
}
if (!found)
{
TreeNode[] newNodes = new TreeNode[target.Length + 1];
Array.Copy(target, newNodes, target.Length);
newNodes[target.Length] = s;
target = newNodes;
}
}
return target;
}
If you are using the Node.Name attribute to set the actual path of the item, then a merge is somewhat simple.
First, create a TreeNodeCollection extension like so (this is needed to have a Case Sensitive Find() method for the TreeNodeCollection, which ensures that the Unique Path can be unique by Case as well) :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TreeViewApp
{
public static class TreeNodeCollectionExtensions
{
public static TreeNode[] FindExact(this TreeNodeCollection coll, string keytofind)
{
TreeNode[] retval;
if (String.IsNullOrWhiteSpace(keytofind) || coll == null)
{
retval = new TreeNode[0];
}
else
{
TreeNode[] badfinds = coll.Find(keytofind, true);
List<TreeNode> goodfinds = new List<TreeNode>();
foreach (TreeNode bad in badfinds)
{
if (bad.Name == keytofind)
goodfinds.Add(bad);
}
retval = goodfinds.ToArray();
}
return retval;
}
}
}
Second, fill a treeview with your Source nodes...
Thrid, fill a treeview with your Target nodes...
Fourth, create an empty treeview.
and then, it's as simple as this:
private void btn_Merge_Click(object sender, EventArgs e)
{
//first merge
foreach (TreeNode sourceNode in this.treeview_Source.Nodes)
{
FindOrAdd(sourceNode, ref this.treeview_Merged);
}
//second merge
foreach (TreeNode targetNode in this.treeview_Target.Nodes)
{
FindOrAdd(targetNode, ref this.treeview_Merged);
}
}
private void FindOrAdd(TreeNode FindMe, ref TreeView InHere)
{
TreeNode[] found = InHere.Nodes.FindExact(FindMe.Name);
//if the node is not found, add it at the proper location.
if (found.Length == 0)
{
if (FindMe.Parent != null)
{
TreeNode[] foundParent = InHere.Nodes.FindExact(FindMe.Parent.Name);
if (foundParent.Length == 0)
InHere.Nodes.Add((TreeNode)FindMe.Clone());
else
foundParent[0].Nodes.Add((TreeNode)FindMe.Clone());
}
else
InHere.Nodes.Add((TreeNode)FindMe.Clone());
}
else
{
//if the item was found, check all children.
foreach (TreeNode child in FindMe.Nodes)
FindOrAdd(child, ref InHere);
}
}
Once again, this solution only works if you have unique paths... with the extension, it also accounts for uniqueness at the case level.
I posted this here in the hopes of helping someone who, like me, had to search for a solution for days on end without success and had to build my own.

Categories

Resources