123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- using System.Collections.Generic;
- using UnityEngine;
- namespace XCharts.Runtime
- {
- /// <summary>
- /// the data struct of graph.
- /// ||数据结构-图。
- /// </summary>
- public class Graph
- {
- public bool directed;
- public List<GraphNode> nodes = new List<GraphNode>();
- public List<GraphEdge> edges = new List<GraphEdge>();
- public Dictionary<string, GraphNode> nodeMap = new Dictionary<string, GraphNode>();
- public Dictionary<string, GraphEdge> edgeMap = new Dictionary<string, GraphEdge>();
- public Graph(bool directed)
- {
- this.directed = directed;
- }
- public void Clear()
- {
- nodes.Clear();
- edges.Clear();
- nodeMap.Clear();
- edgeMap.Clear();
- }
- public void Refresh()
- {
- foreach (var node in nodes)
- {
- node.depth = GetNodeDepth(node);
- }
- }
- public static double GetNodesTotalValue(List<GraphNode> nodes)
- {
- double totalValue = 0;
- foreach (var node in nodes)
- {
- totalValue += node.totalValues;
- }
- return totalValue;
- }
- public List<List<GraphNode>> GetDepthNodes()
- {
- List<List<GraphNode>> depthNodes = new List<List<GraphNode>>();
- var maxDepth = GetMaxDepth();
- for (int i = 0; i <= maxDepth; i++)
- {
- depthNodes.Add(new List<GraphNode>());
- }
- foreach (var node in nodes)
- {
- if (node.inDegree == 0)
- {
- depthNodes[0].Add(node);
- }
- else
- {
- int deep = GetNodeDepth(node);
- depthNodes[maxDepth - deep].Add(node);
- }
- }
- return depthNodes;
- }
- public List<GraphNode> GetRootNodes()
- {
- List<GraphNode> rootNodes = new List<GraphNode>();
- foreach (var node in nodes)
- {
- if (node.inDegree == 0)
- {
- rootNodes.Add(node);
- }
- }
- return rootNodes;
- }
- public int GetMaxDepth()
- {
- int maxDepth = 0;
- foreach (var node in nodes)
- {
- int deep = GetNodeDepth(node);
- if (deep > maxDepth)
- {
- maxDepth = deep;
- }
- }
- return maxDepth;
- }
- // public int GetNodeDepth(GraphNode node)
- // {
- // int depth = 0;
- // GetNodeDepth(node, ref depth);
- // return depth;
- // }
- // public void GetNodeDepth(GraphNode node, ref int depth, int recursiveCount = 0)
- // {
- // if (recursiveCount > 50)
- // {
- // XLog.Error("Graph.GetNodeDeep(): recursiveCount > 50, maybe graph is ring");
- // return;
- // }
- // if (node.inDegree == 0)
- // {
- // return;
- // }
- // else
- // {
- // depth += 1;
- // foreach (var edge in node.inEdges)
- // {
- // GetNodeDepth(edge.node1, ref depth, recursiveCount + 1);
- // }
- // }
- // }
- public int GetNodeDepth(GraphNode node, int recursiveCount = 0)
- {
- if (recursiveCount > 50)
- {
- XLog.Error("Graph.GetNodeDeep(): recursiveCount > 50, maybe graph is ring");
- return 0;
- }
- int depth = 0;
- if (node.outDegree == 0)
- {
- return depth;
- }
- else
- {
- foreach (var edge in node.outEdges)
- {
- int otherDeep = GetNodeDepth(edge.node2, recursiveCount + 1);
- if (otherDeep > depth)
- {
- depth = otherDeep;
- }
- }
- return depth + 1;
- }
- }
- public GraphNode GetNode(string nodeId)
- {
- if (nodeMap.ContainsKey(nodeId))
- {
- return nodeMap[nodeId];
- }
- else
- {
- return null;
- }
- }
- public GraphEdge GetEdge(string nodeId1, string nodeId2)
- {
- if (directed)
- {
- return edgeMap[nodeId1 + "_" + nodeId2];
- }
- else
- {
- var key = nodeId1 + "_" + nodeId2;
- if (edgeMap.ContainsKey(key))
- {
- return edgeMap[key];
- }
- else
- {
- key = nodeId2 + "_" + nodeId1;
- if (edgeMap.ContainsKey(key))
- {
- return edgeMap[key];
- }
- else
- {
- return null;
- }
- }
- }
- }
- public GraphNode AddNode(string nodeId, string nodeName, int dataIndex)
- {
- if (nodeMap.ContainsKey(nodeId))
- {
- return nodeMap[nodeId];
- }
- else
- {
- GraphNode node = new GraphNode(nodeId, nodeName, dataIndex);
- node.hostGraph = this;
- nodeMap.Add(nodeId, node);
- nodes.Add(node);
- return node;
- }
- }
- public GraphEdge AddEdge(string nodeId1, string nodeId2, double value)
- {
- GraphNode node1, node2;
- if (!nodeMap.TryGetValue(nodeId1, out node1))
- {
- XLog.Warning("Graph.AddEdge(): " + nodeId1 + " not exist");
- return null;
- }
- if (!nodeMap.TryGetValue(nodeId2, out node2))
- {
- XLog.Warning("Graph.AddEdge(): " + nodeId2 + " not exist");
- return null;
- }
- if (node1 == null)
- {
- XLog.Warning("Graph.AddEdge(): node1 is null");
- return null;
- }
- if (node2 == null)
- {
- XLog.Warning("Graph.AddEdge(): node2 is null");
- return null;
- }
- if (node1 == node2)
- {
- XLog.Warning("Graph.AddEdge(): node1 == node2");
- return null;
- }
- string edgeKey = nodeId1 + "_" + nodeId2;
- if (edgeMap.ContainsKey(edgeKey))
- {
- return edgeMap[edgeKey];
- }
- else
- {
- GraphEdge edge = new GraphEdge(node1, node2, value);
- edge.key = edgeKey;
- edge.hostGraph = this;
- if (directed)
- {
- node1.outEdges.Add(edge);
- node2.inEdges.Add(edge);
- }
- node1.edges.Add(edge);
- if (node1 != node2)
- {
- node2.edges.Add(edge);
- }
- edgeMap.Add(edgeKey, edge);
- edges.Add(edge);
- return edge;
- }
- }
- public void EachNode(System.Action<GraphNode> onEach)
- {
- if (onEach == null) return;
- foreach (var node in nodes)
- {
- onEach(node);
- }
- }
- public void BreadthFirstTraverse(GraphNode startNode, System.Action<GraphNode> onTraverse)
- {
- if (startNode == null) return;
- foreach (var node in nodes)
- {
- node.visited = false;
- }
- onTraverse(startNode);
- startNode.visited = true;
- Queue<GraphNode> queue = new Queue<GraphNode>();
- queue.Enqueue(startNode);
- while (queue.Count > 0)
- {
- var currentNode = queue.Dequeue();
- foreach (var edge in currentNode.edges)
- {
- var otherNode = edge.node1 == currentNode ? edge.node2 : edge.node1;
- if (!otherNode.visited)
- {
- onTraverse(otherNode);
- otherNode.visited = true;
- queue.Enqueue(otherNode);
- }
- }
- }
- }
- public void DeepFirstTraverse(GraphNode startNode, System.Action<GraphNode> onTraverse)
- {
- if (startNode == null) return;
- foreach (var node in nodes)
- {
- node.visited = false;
- }
- Stack<GraphNode> stack = new Stack<GraphNode>();
- stack.Push(startNode);
- while (stack.Count > 0)
- {
- var currentNode = stack.Pop();
- if (!currentNode.visited)
- {
- onTraverse(currentNode);
- currentNode.visited = true;
- }
- foreach (var edge in currentNode.edges)
- {
- var otherNode = edge.node1 == currentNode ? edge.node2 : edge.node1;
- if (!otherNode.visited)
- {
- stack.Push(otherNode);
- }
- }
- }
- }
- }
- /// <summary>
- /// The node of graph.
- /// ||图的节点。
- /// </summary>
- public class GraphNode
- {
- public string id;
- public string name;
- public List<GraphEdge> edges = new List<GraphEdge>();
- public List<GraphEdge> inEdges = new List<GraphEdge>();
- public List<GraphEdge> outEdges = new List<GraphEdge>();
- public Graph hostGraph;
- public int dataIndex;
- public bool visited;
- public int depth = -1;
- public GraphNode(string id, string name, int dataIndex)
- {
- this.id = id;
- this.name = name;
- this.dataIndex = dataIndex;
- }
- public int degree { get { return edges.Count; } }
- public int inDegree { get { return inEdges.Count; } }
- public int outDegree { get { return outEdges.Count; } }
- public double totalValues
- {
- get
- {
- double totalValue = 0;
- if (inEdges.Count == 0)
- {
- foreach (var edge in outEdges)
- {
- totalValue += edge.value;
- }
- }
- else
- {
- foreach (var edge in inEdges)
- {
- totalValue += edge.value;
- }
- }
- return totalValue;
- }
- }
- public override string ToString()
- {
- return name;
- }
- }
- /// <summary>
- /// The edge of graph.
- /// ||图的边。
- /// </summary>
- public class GraphEdge
- {
- public string key;
- public GraphNode node1;
- public GraphNode node2;
- public double value;
- public Graph hostGraph;
- public List<Vector3> points = new List<Vector3>();
- public float width;
- public bool highlight;
- public GraphEdge(GraphNode node1, GraphNode node2, double value)
- {
- this.node1 = node1;
- this.node2 = node2;
- this.value = value;
- }
- }
- }
|