Cycle enumeration of a directed graph with multi edges [closed] - c#

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
How can I find all cyles in a directed graph with multi edges?
Graph example 1:
Cycles:
1-2-6
1-2-3-4
1-2-3-4-5-6
1-2-6-5-3-4
3-4-5
5-6
Graph example 2 (multi-edge 4/5):
Cycles:
1-2-3
1-4
1-5
Notes:
I don't want to detect a cycle (boolean result), I want to list all cycles.
Any Strongly connected component algorithm is not sufficient for my problem (it would find only one component in both examples).
I'm using the QuickGraph implementation in C#, but I would be happy to see an algorithm in any language.

I had fun with this question, thanks! :P
I have a solution in C#. The algorithm to find the cycles is very short(~10 lines), but there is a lot of clutter around it(implementations of the classes Node and Edge for instance).
I've used the variable naming convention that the letter "e" represents an edge, the letter "a" the node where the edge start, and "b" the node it links to. With those conventions, this is the algorithm:
public static IEnumerable<Cycle> FindAllCycles()
{
HashSet<Node> alreadyVisited = new HashSet<Node>();
alreadyVisited.Add(Node.AllNodes[0]);
return FindAllCycles(alreadyVisited, Node.AllNodes[0]);
}
private static IEnumerable<Cycle> FindAllCycles(HashSet<Node> alreadyVisited, Node a)
{
for (int i = 0; i < a.Edges.Count; i++)
{
Edge e = a.Edges[i];
if (alreadyVisited.Contains(e.B))
{
yield return new Cycle(e);
}
else
{
HashSet<Node> newSet = i == a.Edges.Count - 1 ? alreadyVisited : new HashSet<Node>(alreadyVisited);
newSet.Add(e.B);
foreach (Cycle c in FindAllCycles(newSet, e.B))
{
c.Build(e);
yield return c;
}
}
}
}
It has an optimization to reuse some Hashsets, and that might be confusing. I've included the following code, which produces exactly the same results, but this implementation doesn't have optimizations, so you can figure out more easily how it works.
private static IEnumerable<Cycle> FindAllCyclesUnoptimized(HashSet<Node> alreadyVisited, Node a)
{
foreach (Edge e in a.Edges)
if (alreadyVisited.Contains(e.B))
yield return new Cycle(e);
else
{
HashSet<Node> newSet = new HashSet<Node>(alreadyVisited);
newSet.Add(e.B);//EDIT: thnx dhsto
foreach (Cycle c in FindAllCyclesUnoptimized(newSet, e.B))
{
c.Build(e);
yield return c;
}
}
}
This uses the following implementations of Node, Edge and Cycle. They're pretty straightforward, although I did put a lot of thought in making everything immutable and members as least accessible as possible.
public sealed class Node
{
public static readonly ReadOnlyCollection<Node> AllNodes;
internal static readonly List<Node> allNodes;
static Node()
{
allNodes = new List<Node>();
AllNodes = new ReadOnlyCollection<Node>(allNodes);
}
public static void SetReferences()
{//call this method after all nodes have been created
foreach (Edge e in Edge.AllEdges)
e.A.edge.Add(e);
}
//All edges linking *from* this node, not to it.
//The variablename "Edges" it quite unsatisfactory, but I couldn't come up with anything better.
public ReadOnlyCollection<Edge> Edges { get; private set; }
internal List<Edge> edge;
public int Index { get; private set; }
public Node(params int[] nodesIndicesConnectedTo)
{
this.edge = new List<Edge>(nodesIndicesConnectedTo.Length);
this.Edges = new ReadOnlyCollection<Edge>(edge);
this.Index = allNodes.Count;
allNodes.Add(this);
foreach (int nodeIndex in nodesIndicesConnectedTo)
new Edge(this, nodeIndex);
}
public override string ToString()
{
return this.Index.ToString();
}
}
public sealed class Edge
{
public static readonly ReadOnlyCollection<Edge> AllEdges;
static readonly List<Edge> allEdges;
static Edge()
{
allEdges = new List<Edge>();
AllEdges = new ReadOnlyCollection<Edge>(allEdges);
}
public int Index { get; private set; }
public Node A { get; private set; }
public Node B { get { return Node.allNodes[this.bIndex]; } }
private readonly int bIndex;
internal Edge(Node a, int bIndex)
{
this.Index = allEdges.Count;
this.A = a;
this.bIndex = bIndex;
allEdges.Add(this);
}
public override string ToString()
{
return this.Index.ToString();
}
}
public sealed class Cycle
{
public readonly ReadOnlyCollection<Edge> Members;
private List<Edge> members;
private bool IsComplete;
internal void Build(Edge member)
{
if (!IsComplete)
{
this.IsComplete = member.A == members[0].B;
this.members.Add(member);
}
}
internal Cycle(Edge firstMember)
{
this.members = new List<Edge>();
this.members.Add(firstMember);
this.Members = new ReadOnlyCollection<Edge>(this.members);
}
public override string ToString()
{
StringBuilder result = new StringBuilder();
foreach (var member in this.members)
{
result.Append(member.Index.ToString());
if (member != members[members.Count - 1])
result.Append(", ");
}
return result.ToString();
}
}
Then to illustrate how you might use this small API, I have implemented your two examples.
Basically it comes down to, create all the nodes by specifying to which nodes they link, then call SetReferences() to, well.... set some references. After that, calling the publicly accessible FindAllCycles() should return all cycles. I've excluded any code to reset the static members, but that is easily implemented. It should just clear all static lists.
static void Main(string[] args)
{
InitializeExampleGraph1();//or: InitializeExampleGraph2();
Node.SetReferences();
var allCycles = FindAllCycles().ToList();
}
static void InitializeExampleGraph1()
{
new Node(1, 2);//says that the first node(node a) links to b and c.
new Node(2);//says that the second node(node b) links to c.
new Node(0, 3);//says that the third node(node c) links to a and d.
new Node(0);//etc
}
static void InitializeExampleGraph2()
{
new Node(1);
new Node(0, 0, 2);
new Node(0);
}
I must note that the indices of the edges in these examples do NOT correspond to the indices in your images, but that is avoidable with a simple lookup.
The results: allCycles is for the first example:
{3, 2, 0}
{5, 4, 2, 0}
{3, 1}
{5, 4, 1}
allCycles is for the second example:
{1, 0}
{2, 0}
{4, 3, 0}
I hope you are satisfied with this solution and that you use it. I've barely commented on the code, so I know it might be hard to understand. In that case, please ask and I'll comment on it!

What about using Breadth-first search to find all paths between nodes A and B - lets call that function get_all_paths
To find all cycles you just need to:
cycles = []
for x in nodes:
cycles += get_all_paths(x,x)
get_all_paths(x,x) because a cycle is just a path that starts and ends in the same node.
Just an alternative solution - I hope it gives new ideas.
Edit
Another option is to compute all the posible paths and check every time that the first edge starts where the last edge finishes - a cycle.
Here you can see the Python code for it.
def paths_rec(path,edges):
if len(path) > 0 and path[0][0] == path[-1][1]:
print "cycle", path
return #cut processing when find a cycle
if len(edges) == 0:
return
if len(path) == 0:
#path is empty so all edges are candidates for next step
next_edges = edges
else:
#only edges starting where the last one finishes are candidates
next_edges = filter(lambda x: path[-1][1] == x[0], edges)
for edge in next_edges:
edges_recursive = list(edges)
edges_recursive.remove(edge)
#recursive call to keep on permuting possible path combinations
paths_rec(list(path) + [edge], edges_recursive)
def all_paths(edges):
paths_rec(list(),edges)
if __name__ == "__main__":
#edges are represented as (node,node)
# so (1,2) represents 1->2 the edge from node 1 to node 2.
edges = [(1,2),(2,3),(3,4),(4,2),(2,1)]
all_paths(edges)

JBSnorro gave an awesome answer, but still it might seem a little too hardcore. Starting from his solution, i present an easier to follow example, that does not need the definitions of Node, Edge and Cycle, and also works on adjacency matrices. My solution though, repeats some cycles if they are started from a different node.
int[,] Adjacency = new int[6, 6] {
{ 0,1,0,1,0,0 },
{ 0,0,0,1,0,0 },
{ 0,0,0,0,1,0 },
{ 0,1,1,0,0,0 },
{ 0,1,0,0,0,1 },
{ 0,0,1,1,0,0 }};
public void Start()
{
List<List<int>> Out = new List<List<int>>();
FindAllCycles(new List<int>(), Out, 0);
Console.WriteLine("");
foreach (List<int> CurrCycle in Out)
{
string CurrString = "";
foreach (int Currint in CurrCycle) CurrString += Currint + ", ";
Console.WriteLine(CurrString);
}
}
private void FindAllCycles(List<int> CurrentCycleVisited, List<List<int>> Cycles, int CurrNode)
{
CurrentCycleVisited.Add(CurrNode);
for (int OutEdgeCnt = 0; OutEdgeCnt < Adjacency.GetLength(0); OutEdgeCnt++)
{
if (Adjacency[CurrNode, OutEdgeCnt] == 1)//CurrNode Is connected with OutEdgeCnt
{
if (CurrentCycleVisited.Contains(OutEdgeCnt))
{
int StartIndex = CurrentCycleVisited.IndexOf(OutEdgeCnt);
int EndIndex = CurrentCycleVisited.IndexOf(CurrNode);
Cycles.Add(CurrentCycleVisited.GetRange(StartIndex, EndIndex - StartIndex + 1));
}
else
{
FindAllCycles(new List<int>(CurrentCycleVisited), Cycles, OutEdgeCnt);
}
}
}
}

Related

How to implement user inputted integers in a sorted linked list?

As stated in in the title, I would like to know how to allow the user to push the integers and print them. I have written another simple program where the user can press keys to do a few things, like push/pop/print, would it be possible to merge them even if the one is just an ordinary stack and another is a linked list?
This is is the first program that simply lets the user add a string, push/pop/print:
class Program
{
static void Main(string[] args)
{
Stack<string> mystack = new Stack <string>();
int number = -1;
while (number != 0)
{
Console.WriteLine("1- enter string");
Console.WriteLine("2 - delete string");
Console.WriteLine("3- print all strings");
Console.WriteLine("0- Exit");
number = Convert.ToInt32(Console.ReadLine());
{
switch (number)
{
case 1:
Console.Write("Enter string: ");
mystack.Push(Console.ReadLine());
break;
case 2:
mystack.Pop();
Console.WriteLine("first string deleted");
break;
case 3:
foreach (string i in mystack)
{
Console.WriteLine(i);
}
break;
}
}
}
Console.ReadKey();
}
}
}
This is the second which is a linked list sorted in ascending order but the integers are inputted by the coder.
{
class LinkedList
{
public class node
{
public int data;
public node next;
};
static node start;
static void sortList(node head)
{
int startVal = 1;
while (head != null)
{
head.data = startVal;
startVal++;
head = head.next;
}
}
static void push(node head_ref,
int new_data)
{
node new_node = new node();
new_node.data = new_data;
new_node.next = head_ref;
head_ref = new_node;
start = head_ref;
}
static void printList(node node)
{
while (node != null)
{
Console.Write(node.data + " ");
node = node.next;
}
}
public static void Main(String[] args)
{
start = null;
push(start, 2);
push(start, 1);
push(start, 6);
push(start, 4);
push(start, 5);
push(start, 3);
sortList(start);
printList(start);
Console.ReadKey();
}
You are trying to merge the functionality of two different data types that have different usage.
Stack and Linked List are two linear data structures. A programmer can implement them using any programming language. The main difference between Stack and Linked List is that a Stack works according to the FIFO mechanism while a Linked List works by storing the data and the addresses of other nodes to refer to each other.
In a stack, the topmost element can be read. On the other hand, in a linked list, if the programmer wants to access a specific element, it is necessary to traverse each element from the beginning.
Though you can use the combination of both in such a way to push the data to stack in a sorted manner.
Reference: https://pediaa.com/what-is-the-difference-between-stack-and-linked-list/#:~:text=A%20stack%20is%20an%20abstract,between%20stack%20and%20linked%20list.

SortedSet.Remove () not working with custom comparer class

I am trying to solve a leetcode problem, where I want to get top k frequent numbers. I am trying to solve it using SortedSet for O(log n) time complexity.
My code is working for all inputs except one particular input.
public class FreqNode
{
public int number;
public int freq;
public FreqNode(int n, int f)
{
number = n;
freq = f;
}
}
class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 3, 2, 3, 1, 2, 4, 5, 5, 6, 7, 7, 8, 2, 3, 1, 1, 1, 10, 11, 5, 6, 2, 4, 7, 8, 5, 6};
TopKFrequent(arr, 10);
Console.Read();
}
static void TopKFrequent(int[] nums, int k)
{
SortedSet<FreqNode> sl = new SortedSet<FreqNode>(new MyComparer());
Dictionary<int, FreqNode> ht = new Dictionary<int, FreqNode>();
foreach (int i in nums)
{
if (ht.ContainsKey(i))
{
sl.Remove(ht[i]);
ht[i].freq += 1;
}
else
{
ht[i] = new FreqNode(i, 1);
}
sl.Add(ht[i]);
}
for (int i = 0; i < k; i++)
{
FreqNode f = sl.ElementAt(i);
Console.WriteLine(f.number);
}
}
}
public class MyComparer : IComparer<FreqNode>
{
public int Compare(FreqNode fn1, FreqNode fn2)
{
//Remove entry with same number
//Retain entries with same frequencies.
if (fn1.number == fn2.number)
{
return 0;
}
else
{
int res = fn2.freq.CompareTo(fn1.freq);
if (res == 0)
{
return 1;
}
else
{
return res;
}
}
}
}
It prints output as - 1,2,5,3,7,6,6,4,8,10
instead of - 1,2,5,3,6,7,4,8,10,11
During debugging, I noticed that Comparer code does not compare with existing entry of number 6. After further investigation, I found that, SortedSet is implemented using Red-Black tree, but I could not resolve this bug in my code.
This problem was interesting to me because I thought it might be a SortedSet bug and had me stepping through the SortedSet source. Alas, not a SortedSet bug...sorry but your IComparer is a bit wonky.
Your IComparer implementation does weird things to the comparison by first changing the criteria of sort comparison, then by inverting the comparison objects, then by changing the return value.
First your comparer is saying,
if "number" properties are equal, the nodes are equal (this is fine)
if (fn1.number == fn2.number)
{
return 0;
}
then it's saying
sort on the inverse of the freq property (switching fn2 with fn1 is probably not a good idea, and the criteria of sort has changed to the 'freq' property (probably ok))
int res = fn2.freq.CompareTo(fn1.freq);
then it's changing equal freqs to not be equal
if the result of the 'freq' comparison was equal, let's pretend like it's not equal (probably not a good idea)
if (res == 0)
{
return 1;
}
The poor SortedSet's root must be rotating!! (HAHAHA!! I made a Data Structures joke!! get it "root"? "rotating"?)
In the end, the Remove algorithm looks for the '6' as a right child because your IComparer tells it that's where it should be, meanwhile '6' is actually a left child, so the Remove algorithm misses it.
As an aside, keep in mind that the 2 '6' nodes in your SortedSet and the '6' node in your dictionary are all actually the same FreqNode reference, so you can change all of them at the same time if you needed to.
You can look at (and download) the .NET source here
then set up Visual Studio to debug sources by following the instructions here
Lastly, if you insist solving the top-k problem this way, try this comparer:
public class MyComparer : IComparer<FreqNode>
{
public int Compare(FreqNode fn1, FreqNode fn2)
{
return fn1.number == fn2.number ? fn1.freq.CompareTo(fn2.freq) : fn1.number.CompareTo(fn2.number);
}
}
Cheers and thanks for a fun debug!

Determine if a tree is balanced or not in linear time

The following programme returns whether a tree is balanced or not. A tree is said to be balanced if a path from the root to any leaf has the same length.
using System;
namespace BalancedTree
{
public class MainClass
{
static bool isBalanced(int[][] sons)
{
return isBalanced(sons, 0);
}
static bool isBalanced(int[][] sons, int startNode)
{
int[] children = sons[startNode];
int minHeight = int.MaxValue;
int maxHeight = int.MinValue;
bool allChildBalanced = true;
if(children.Length == 0)
return true;
else
{
foreach (int node in children)
{
int h = height(sons, node);
if(h > maxHeight)
maxHeight = h;
if(h < minHeight)
minHeight = h;
}
}
foreach (int node in children)
{
allChildBalanced = allChildBalanced && isBalanced(sons, node);
if(!allChildBalanced)
return false;
}
return Math.Abs(maxHeight - minHeight) < 2 && allChildBalanced;
}
static int height(int[][] sons, int startNode)
{
int maxHeight = 0;
foreach (int child in sons[startNode])
{
int thisHeight = height(sons, child);
if(thisHeight > maxHeight)
maxHeight = thisHeight;
}
return 1 + maxHeight;
}
public static void Main (string[] args)
{
int[][] sons = new int[6][];
sons[0] = new int[] { 1, 2, 4 };
sons[1] = new int[] { };
sons[2] = new int[] { 3, 5};
sons[3] = new int[] { };
sons[4] = new int[] { };
sons[5] = new int[] { };
Console.WriteLine (isBalanced(sons));
}
}
}
My problem is that my code is very inefficient, due to recursive calls to function
static int height(int[][] sons, int startNode)
making the time complexity exponential.
I know this can be optimised in case of a binary tree, but I'm looking for a way to optimise my programme in case of a general tree as described above.
One idea would be for instance to call function 'height' from the current node instead of startNode.
My only constraint is time complexity which must be linear, but I can use additional memory.
Sorry, but I have never done C#. So, there will be no example code.
However, it shouldn't be too hard for you to do it.
Defining isBalanced() recursively will never give best performance. The reason is simple: A tree can still be unbalanced, if all sub-trees are balanced. So, you can't just traverse the tree once.
However, your height() function already does the right thing. It visits every node in the tree only once to find the height (i.e. maximum length from the root to a leaf).
All you have to do is write a minDistance() function that finds the minimum length from the root to a leaf. You can do this using almost the same code.
With these functions a tree is balanced if and only if height(...)==minDistance(...).
Finally, you can merge both function into one that returns a (min,max) pair. This will not change time complexity but could bring down execution time a bit, if returning pairs is not too expensive in C#

C# Recursive Permutation is Possible? (beginner)

Hi guys im trying to learn permutation and recurtion. And im looking for a way how can i use bought at the same time.
MAIN:
namespace Recursive_Permutation
{
class Program
{
static void Main(string[] args)
{
int[] array = new int[5] { 0, 0, 0, 0, 0 };
CalPermutations CP = new CalPermutations();
CP.Run(array, array.Length-1);
}
}
}
Here is my Simple code:
namespace Recursive_Permutation
{
public class CalPermutations
{
public int Run(int[] array,int indexer)
{
if (indexer > array.Length)
{
return 1;
}
else
{
for (int i = 0; i <= array.Length; i++)
{
array[indexer] = i;
Display(array);
}
Run(array, indexer-1);
}
return indexer;
}
public void Display(int[] array)
{
foreach (int num in array)
{
Console.Write(num);
}
Console.WriteLine();
}
}
}
And here is the Output of the program:
Question:
it might be simple to other but im kind of confuse now in how can i manipulate it that it still count the first digit (position [0]) 1 to 5 and go next position and (position 1) and add 1 and go back to [0] and start count again till it reaches 5.
i hope that my explanation is understandable.. thx.
I put together this simpler example of using recursion and permutation. It uses strings internally, but produces the same result.
Its for proof of concept only, since nobody will us recursion for this simple stuff in a professional environment. Recursion can have a big memory impact, but makes describing some problems in a simple way possible.
If I had to choose between iterative and recursive solutions, I would take the iterative one most of the time.
// Main entrance
public void DoStuff()
{
// define variations
List<string> possibilities = new List<string>() { "0", "1", "2", "3", "4", "5" };
// resultlist, will be filled later
List<string> permutations = new List<string>();
// how many values will be taken from the possibilities
int digits = 5;
//do the work
Permute(permutations, possibilities, digits, "");
// display the work
foreach (var item in permutations)
{
Console.WriteLine(item);
}
}
/// <summary>
/// generates a List of permuted strings
/// </summary>
/// <param name="permutations">resultlist</param>
/// <param name="possibilities">possible values of the digit</param>
/// <param name="digitsLeft">how many digits shall be appended</param>
/// <param name="current">the current value of the unfinished result</param>
private void Permute(List<string> permutations, List<string> possibilities, int digitsLeft, string current)
{
// uncomment to see how it works in detail
//Console.WriteLine("step:"+current);
// most important: define Stop conditions for the recursion
// safety stop
if (digitsLeft < 0)
{// end of digits :), normally we never end up here
return;
}
// normal stop
if (digitsLeft == 0)
{// normal endpoint, add the found permutation to the resultlist
permutations.Add(current);
return;
}
// now prepare the recursion, try each possibility
foreach (var item in possibilities)
{
// digitsLeft need to be decreased, since we add a concrete digit to the current value (current+item)
// important: (current + item) generates a new string in memory, the old values won't be touched, permutations possibilities are references, so no memory impact here
Permute(permutations, possibilities, digitsLeft - 1, current + item);
}
}
Update: added comments on each method as per comment.
public class Program
{
public static void Main(string[] args)
{
int[] array = new int[] { 0, 0, 0, 0, 0};
CalPermutations CP = new CalPermutations();
CP.Run(array, 0);
}
}
public class CalPermutations
{
// Prints all the permutations of array, starting at the specified index.
public void Run(int[] array, int indexer)
{
if (indexer < 0 || indexer >= array.Length)
return;
// Keep [0, indexer] combination constant, change combination on right i.e. (indexer, Array.length).
Run(array, indexer+1);
// All the elements on right have finished, increment current element.
array[indexer]++;
// Check if current combination is STILL valid.
if(array[indexer] <= array.Length)
{
// since current combination is still valid, display it, and execute the process again on the new combination.
Display(array);
Run(array, indexer);
}
else
{
// Since current element is out of range, reset it.
array[indexer] = 1;
}
}
// Prints all the elements in array.
public void Display(int[] array)
{
foreach (int num in array)
Console.Write(num);
Console.WriteLine();
}
}

BinarySearch on List<T> seems to be returning strange result

I am very new to C#. I have created a List object and then I am performing BinarySearch on a particular item. But the search results seem to strange. Here is the code :
class Element
{
public int x;
public Element(int val) { x = val; }
}
class MyContainer : IComparable<MyContainer>
{
public Element elem;
public MyContainer(int val) { elem = new Element(val); }
public MyContainer(Element e) { elem = e; }
public int CompareTo(MyContainer obj)
{
if (elem.x < obj.elem.x) { return -1; }
else if (elem.x == obj.elem.x) { return 0; }
else { return 1; }
}
}
class Program
{
static void Main(string[] args)
{
MyContainer container1 = new MyContainer(100);
MyContainer container2 = new MyContainer(21);
MyContainer container3 = new MyContainer(-122);
Element elemObj = new Element(-122);
List<MyContainer> list = new List<MyContainer>();
list.Add(new MyContainer(80));
list.Add(container1);
list.Add(container2);
list.Add(container3);
list.Add(new MyContainer(90));
foreach(MyContainer c in list) Console.WriteLine(c.elem.x);
if (list.Contains(container3) == true) Console.WriteLine("present");
else Console.WriteLine("NOT present");
Console.WriteLine("Search result:::"+list.BinarySearch(new MyContainer(elemObj)));
Console.WriteLine("Search result:::" + list.BinarySearch(container1));
Console.WriteLine("Search result:::" + list.BinarySearch(container2));
Console.WriteLine("Search result:::" + list.BinarySearch(container3));
}
}
The output is as follows :
80
100
21
-122
90
present
Search result:::-1
Search result:::-6
Search result:::2
Search result:::-1
Why is only the element corresponding to value 21 found and why not the others
Your list isn't sorted to start with. Binary search only works when the original input is sorted. The whole point is that you know that if list[x] = y, then list[a] <= y for all a < x and list[a] >= y for all a > x.
So either you need to sort your list first, or you need to choose a different way of searching (e.g. using a separate hash-based dictionary, or just doing a linear search).
Also note that your CompareTo method can be implemented a lot more simply:
public int CompareTo(MyContainer obj)
{
return elem.x.CompareTo(obj.elem.x);
}
A BinarySearch only works on a sorted list. Since your list is not sorted in the way it should be, it may or may not find the result correctly. You could fix this by sorting first:
list.Add(new MyContainer(90));
// after adding all elements
list.Sort();
foreach(MyContainer c in list) Console.WriteLine(c.elem.x);

Categories

Resources