private void BFSImpl(ReadOnlyNode startNode, Action <ReadOnlyNode> map) { var queue = new Queue <Node>(); var start = startNode.ThisNode as Node; start.Distance = 0; queue.Enqueue(start); while (queue.Count > 0) { var node = queue.Dequeue(); map?.Invoke(ReadOnlyNode.Create(node).Value); node.Color = NodeColor.Black; // seen and leaving foreach (var edge in node.OutEdges) { var targetNode = edge.NodeTo.ThisNode as Node; if (targetNode.Color == NodeColor.White) { targetNode.Color = NodeColor.Gray; // seen and has not left yet targetNode.Distance = node.Distance + 1; targetNode.PreviousNode = node; queue.Enqueue(targetNode); } } } }
/// <summary> /// Add value to graph and create node for it. /// </summary> /// <param name="value">Value to add</param> /// <returns>Node created for this value</returns> public ReadOnlyNode AddNode(T value) { var node = new Node(value); nodes.Add(node); return(ReadOnlyNode.Create(node).Value); }
/// <summary> /// Remove all nodes that match given predicate. /// </summary> /// <param name="predicate">Predicate to match</param> public void RemoveAllNodes(Predicate <ReadOnlyNode> predicate) { if (predicate == null) { throw new ArgumentNullException("Predicate is null"); } nodes.RemoveAll(node => predicate(ReadOnlyNode.Create(node).Value)); }
/// <summary> /// Run DFS (Depth first search) algorithm. /// </summary> /// <param name="startNode">Starting node</param> /// <param name="map">Node's mapping function</param> public void DFS(ReadOnlyNode startNode, Action <ReadOnlyNode> map) { PrepareForGraphTraverse(); var start = startNode.ThisNode as Node; start.Distance = 0; DFSRecursive(start, null, map); }
/// <summary> /// Add edge to graph. /// </summary> /// <param name="nodeFrom">Source node</param> /// <param name="nodeTo">Target node</param> /// <param name="length">Length (weight) of node</param> /// <returns>Edge added to the graph</returns> public Edge AddEdge(ReadOnlyNode nodeFrom, ReadOnlyNode nodeTo, double length) { var edge = new Edge(length, nodeFrom, nodeTo); (nodeFrom.ThisNode as Node).OutEdges.Add(edge); (nodeTo.ThisNode as Node).InEdges.Add(edge); return(edge); }
/// <summary> /// Swap values in given nodes. /// </summary> /// <param name="nodeA">First node</param> /// <param name="nodeB">Second node</param> public void Swap(ReadOnlyNode nodeA, ReadOnlyNode nodeB) { var swapNodeA = (Node)nodeA.ThisNode; var swapNodeB = (Node)nodeB.ThisNode; var tmpValue = swapNodeA.Value; swapNodeA.Value = swapNodeB.Value; swapNodeB.Value = tmpValue; }
/// <summary> /// Run Bellman-Ford algorithm and count minimum distance from given node. /// </summary> /// <param name="startNode">Starting node</param> public void BellmanFord(ReadOnlyNode startNode) { if (NumberOfConnectivityComponents() > 1) { throw new InvalidOperationException("Unable to perform BellmanFord on graph with more than one connectivity component"); } PrepareForGraphTraverse(); BellmanFordImpl(startNode.ThisNode as Node); }
public Edge(double length, ReadOnlyNode nodeFrom, ReadOnlyNode nodeTo) { unchecked { Id = IdCounter++; } Length = length; NodeFrom = nodeFrom; NodeTo = nodeTo; }
/// <summary> /// Find node with given key. /// </summary> /// <param name="key">Key of node to find</param> /// <returns>Node that contains given key if any found, otherwise null</returns> public ReadOnlyNode?Find(TKey key) { var result = FindNodeImpl(key); if (result.Node != null) { Splay(result.Node); } return(ReadOnlyNode.Create(result.Node)); }
private ReadOnlyNode(IEnumerator <T> elements, ReadOnlyNode <T> prev, bool first) { if (first) { elements.MoveNext(); } Value = elements.Current; Next = elements.MoveNext() ? new ReadOnlyNode <T>(elements, this, false) : null; Prev = prev; }
/// <summary> /// Get node at given index. /// </summary> /// <param name="index">Node's index</param> /// <returns>Node at given index</returns> public ReadOnlyNode this[int index] { get { if (index < 0 || index >= Count) { throw new ArgumentOutOfRangeException("Index out of range"); } return(ReadOnlyNode.Create(nodes[index]).Value); } }
/// <summary> /// Find all nodes with values that match given predicate. /// </summary> /// <param name="predicate">Predicate</param> /// <returns>List of nodes that match given predicate</returns> public List <ReadOnlyNode> FindAll(Predicate <T> predicate) { var list = new List <ReadOnlyNode>(); var node = FindFrom(predicate, frontNode); while (node != null) { list.Add(ReadOnlyNode.Create(node).Value); node = FindFrom(predicate, node.Next); } return(list); }
private ReadOnlyNode(IEnumerable <T> elements, ReadOnlyNode <T> prev) { if (elements == null || !elements.Any()) { throw new ArgumentException( "Enumerable must not be null and must have at least one element"); } Next = elements.Count() == 1 ? null : new ReadOnlyNode <T>(elements.Skip(1), this); Value = elements.First(); Prev = prev; }
/// <summary> /// Remove first node that match given predicate. /// </summary> /// <param name="predicate">Predicate to match</param> /// <returns>True if any node was removed, false otherwise</returns> public bool RemoveNode(Predicate <ReadOnlyNode> predicate) { if (predicate == null) { throw new ArgumentNullException("Predicate is null"); } var index = nodes.FindIndex(node => predicate(ReadOnlyNode.Create(node).Value)); if (index >= 0 && index < Count) { RemoveAllEdgesConnectedToNode(nodes[index]); nodes.RemoveAt(index); return(true); } return(false); }
/// <summary> /// Count number connectivity components in graph using BFS. /// </summary> /// <returns>Number of connectivity components in graph</returns> public int NumberOfConnectivityComponents() { PrepareForGraphTraverse(); int componentsCounter = 0; foreach (var node in nodes) { if (node.Color == NodeColor.White) { componentsCounter++; BFS(ReadOnlyNode.Create(node).Value, null); } } ClearTraversingStats(); return(componentsCounter); }
private List <Edge> JarnikImpl() { PrepareForGraphTraverse(); DijkstraImpl(nodes[0], EdgeRelaxJarnik); var spanningTree = new List <Edge>(); foreach (var node in nodes) { if (node.PreviousNode == null) { continue; } var from = ReadOnlyNode.Create(node.PreviousNode).Value; var to = ReadOnlyNode.Create(node).Value; spanningTree.Add(new Edge(node.Distance, from, to)); } return(spanningTree); }
/// <summary> /// Insert value before given node. /// </summary> /// <param name="node">Insert value before this node</param> /// <param name="value">Value to insert</param> public void InsertBefore(ReadOnlyNode node, T value) { if (node.ThisNode == frontNode) { PushFront(value); return; } var nextNode = (Node)node.ThisNode; var newNode = new Node(value) { Previous = nextNode.Previous, Next = nextNode }; nextNode.Previous = newNode; newNode.Previous.Next = newNode; Count++; }
/// <summary> /// Insert value after given node. /// </summary> /// <param name="node">Insert value after this node</param> /// <param name="value">Value to insert</param> public void InsertAfter(ReadOnlyNode node, T value) { if (node.ThisNode == backNode) { PushBack(value); return; } var previousNode = (Node)node.ThisNode; var newNode = new Node(value) { Previous = previousNode, Next = previousNode.Next }; previousNode.Next = newNode; newNode.Next.Previous = newNode; Count++; }
/// <summary> /// Remove node from list. /// </summary> /// <param name="node">Node to remove</param> public void RemoveNode(ReadOnlyNode node) { if (node.ThisNode == frontNode) { PopFront(); return; } if (node.ThisNode == backNode) { PopBack(); return; } var removeNode = (Node)node.ThisNode; removeNode.Previous.Next = removeNode.Next; removeNode.Next.Previous = removeNode.Previous; Count--; }
/// <summary> /// Return node at given index. /// </summary> /// <param name="index">Index of node to return</param> /// <returns>Node at given index</returns> public ReadOnlyNode NodeAt(int index) { if (index < 0 || index >= Count) { throw new ArgumentOutOfRangeException("Index is out of range"); } var node = frontNode; for (int i = 0; i < index && node != null; i++) { node = node.Next; } if (node == null) { throw new InvalidOperationException("Linked list is corrupted"); } return(ReadOnlyNode.Create(node).Value); }
private void DFSRecursive(Node node, Node previousNode, Action <ReadOnlyNode> map) { if (node.Color == NodeColor.White) { node.PreviousNode = previousNode; node.Distance = previousNode != null ? previousNode.Distance + 1 : 0; } // In case of cycle detection map?.Invoke(ReadOnlyNode.Create(node).Value); if (node.Color != NodeColor.White) { return; } node.Color = NodeColor.Gray; foreach (var edge in node.OutEdges) { DFSRecursive(edge.NodeTo.ThisNode as Node, node, map); } node.Color = NodeColor.Black; }
private ReadOnlyNode(IEnumerator <T> elements, ReadOnlyNode <T> prev, bool first) { if (elements == null) { throw new ArgumentNullException("elements"); } var empty = false; if (first) { empty = elements.MoveNext(); } if (!empty) { Value = elements.Current; Next = elements.MoveNext() ? new ReadOnlyNode <T>(elements, this, false) : null; Prev = prev; } }
/// <summary> /// Check whether graph contains a cycle (using DFS). /// </summary> /// <returns>True whether graph containst cycle, false otherwise</returns> public bool ContainsCycle() { PrepareForGraphTraverse(); bool cycleDetected = false; foreach (var node in nodes) { if (node.Color == NodeColor.White) { DFS(ReadOnlyNode.Create(node).Value, (readOnlyNode) => { cycleDetected = (readOnlyNode.ThisNode as Node).Color == NodeColor.Gray; }); if (cycleDetected) { break; } } } ClearTraversingStats(); return(cycleDetected); }
/// <summary> /// Add element (key-value pair) to tree. /// </summary> /// <param name="key">Element's key</param> /// <param name="value">Element's value</param> /// <returns>Added node</returns> public ReadOnlyNode Add(TKey key, TValue value) { if (root == null) // Insert root { root = new Node(key, value, null); Count = 1; return(Root.Value); } var result = FindNodeImpl(key); var node = result.Node; if (node != null) // Key-Value already present, just overwrite current value { node.Value = value; } else { node = InsertNewNode(key, value, result.ParentNode); } return(ReadOnlyNode.Create(node).Value); }
/// <summary> /// Run Dijkstra algorithm and count minimum distance from given node. /// </summary> /// <param name="startNode">Starting node</param> public void Dijkstra(ReadOnlyNode startNode) { PrepareForGraphTraverse(); DijkstraImpl(startNode.ThisNode as Node, EdgeRelax); }
/// <summary> /// Return index of given node in graph. /// </summary> /// <param name="readOnlyNode">Node to find out an index in graph</param> /// <returns>Index of given node</returns> public int GetIndex(ReadOnlyNode readOnlyNode) => nodes.FindIndex(node => node.Id == (readOnlyNode.ThisNode as Node).Id);
/// <summary> /// Return first node that match given predicate. /// </summary> /// <param name="predicate">Predicate</param> /// <returns>Node with value that match given predicate, otherwise null</returns> public ReadOnlyNode?Find(Predicate <T> predicate) => ReadOnlyNode.Create(FindFrom(predicate, frontNode));
public Node(T value, ReadOnlyNode <T> next, ReadOnlyNode <T> prev) { Value = value; Next = next; Prev = prev; }
/// <summary> /// Run BFS (Breadth first search) algorithm. /// </summary> /// <param name="startNode">Starting node</param> /// <param name="map">Node's mapping function</param> public void BFS(ReadOnlyNode startNode, Action <ReadOnlyNode> map) { PrepareForGraphTraverse(); BFSImpl(startNode, map); }
/// <summary> /// Remove given node from graph with all it's in/out going edges. /// </summary> /// <param name="readOnlyNode">Node to remove</param> public void RemoveNode(ReadOnlyNode readOnlyNode) => RemoveNode(node => (node.ThisNode as Node).Id == (readOnlyNode.ThisNode as Node).Id);