|
@@ -0,0 +1,437 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Linq;
|
|
|
+namespace SAGA.DotNetUtils.Data
|
|
|
+{
|
|
|
+ #region 概述
|
|
|
+ /*
|
|
|
+ * 有向图,和无向图,部分方法不同;
|
|
|
+ *
|
|
|
+ * 内部操作使用索引;功能扩展使用Data
|
|
|
+ */
|
|
|
+ #endregion
|
|
|
+ /// <summary>
|
|
|
+ /// 边集列表
|
|
|
+ /// </summary>
|
|
|
+ public class EdgesArrayGraph<V,VD,E,ED> : EdgesArrayBase<V, VD, E, ED> where V : EAVertex<VD> ,new() where E : EAEdge<ED>,new()
|
|
|
+ {
|
|
|
+ public EdgesArrayGraph()
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+ #region 控制属性
|
|
|
+ /// <summary>
|
|
|
+ /// 表示该图信息是否是有向的
|
|
|
+ /// </summary>
|
|
|
+ public bool IsDirection { get; set; }
|
|
|
+ #endregion
|
|
|
+ #region 编号系统
|
|
|
+ private int m_CurrentVertexIndex;
|
|
|
+ /// <summary>
|
|
|
+ /// 生成节点索引
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private string GenerateVertexIndex()
|
|
|
+ {
|
|
|
+ return "V" + (++m_CurrentVertexIndex);
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 生成节点索引
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private string GenerateEdgeIndex()
|
|
|
+ {
|
|
|
+ return "E" + (++m_CurrentVertexIndex);
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 点操作
|
|
|
+
|
|
|
+ #region 查找点
|
|
|
+ /// <summary>
|
|
|
+ /// 根据顶点Id查询相应的节点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="vertexId"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public virtual V FindVertex(string vertexId)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrWhiteSpace(vertexId))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (this.m_Vertexes.Contains(vertexId))
|
|
|
+ {
|
|
|
+ return this.m_Vertexes[vertexId];
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 根据顶点Id查询相应的节点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="v">根据顶点信息去检索点</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public virtual V FindVertex(V v)
|
|
|
+ {
|
|
|
+ /*
|
|
|
+ * 待改进:id快索引,IsMatch值匹配慢索引
|
|
|
+ */
|
|
|
+ var useV = FindVertex(v.Id) ?? this.Vertexes.FirstOrDefault(c => c.IsMatch(v));
|
|
|
+ return useV;
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 增加点
|
|
|
+ /// <summary>
|
|
|
+ /// 增加顶点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="vertex"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public virtual V AddVertex(V vertex)
|
|
|
+ {
|
|
|
+ if (vertex == null)
|
|
|
+ return null;
|
|
|
+ V result = vertex;
|
|
|
+ var useVertex = FindVertex(vertex);
|
|
|
+ if (useVertex == null)
|
|
|
+ {
|
|
|
+ vertex.Id = GenerateVertexIndex();
|
|
|
+ this.m_Vertexes.Add(vertex);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ useVertex.Merge(vertex);
|
|
|
+ result = useVertex;
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 增加顶点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="vData"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public virtual V AddVertex(VD vData)
|
|
|
+ {
|
|
|
+ if (vData == null)
|
|
|
+ return null;
|
|
|
+ var v = new V();
|
|
|
+ v.Data = vData;
|
|
|
+ return AddVertex(v);
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 移除点相关操作
|
|
|
+ /// <summary>
|
|
|
+ /// 根据Id移除节点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="vertexId"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public virtual bool RemoveVertex(string vertexId)
|
|
|
+ {
|
|
|
+ var realRemove = this.m_Vertexes.Remove(vertexId);
|
|
|
+ if (realRemove)
|
|
|
+ {
|
|
|
+ //移除节点需要移除相应的边
|
|
|
+ #region 移除相关联的边
|
|
|
+ var edges = this.Edges.Where(e => e.ContainVertex(vertexId) > -1);
|
|
|
+ foreach (var edge in edges)
|
|
|
+ {
|
|
|
+ this.m_Edges.Remove(edge.Id);
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ }
|
|
|
+ return realRemove;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 隐藏点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="vertexId"></param>
|
|
|
+ public virtual void HideVertex(string vertexId)
|
|
|
+ {
|
|
|
+ /*
|
|
|
+ * 将指定点隐藏:概念上是将该点关联的边和点信息删除重构;
|
|
|
+ * 一般适用于三点一线,隐藏掉中间点的情况;
|
|
|
+ * 其他情况下,边关联信息可能会出现问题
|
|
|
+ */
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 合并点
|
|
|
+ /// <summary>
|
|
|
+ /// 合并关联的点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="vs"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public virtual V CombineVertexes(List<V> vs)
|
|
|
+ {
|
|
|
+ //将关联点合并。1、将点与点之间的边信息进行处理;2、创建新的点
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 边操作
|
|
|
+ #region 查找边
|
|
|
+ /// <summary>
|
|
|
+ /// 获取边信息
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="edgeId"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public E FindEdge(string edgeId)
|
|
|
+ {
|
|
|
+ if (this.m_Edges.Contains(edgeId))
|
|
|
+ {
|
|
|
+ return m_Edges[edgeId];
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+ #region 增加边
|
|
|
+ /// <summary>
|
|
|
+ /// 增加边
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="edge"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public virtual E AddEdge(E edge)
|
|
|
+ {
|
|
|
+ var start = FindVertex(edge.StartVertex);
|
|
|
+ if (start == null)
|
|
|
+ throw new Exception("start元素必须在图中");
|
|
|
+ var end = FindVertex(edge.EndVertex);
|
|
|
+ if (end == null)
|
|
|
+ throw new Exception("end元素必须在图中");
|
|
|
+ edge.Id = GenerateEdgeIndex();
|
|
|
+ this.m_Edges.Add(edge);
|
|
|
+ return edge;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 增加边信息
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="start"></param>
|
|
|
+ /// <param name="end"></param>
|
|
|
+ /// <param name="edge"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public virtual E AddEdge(V start, V end, E edge)
|
|
|
+ {
|
|
|
+ var startV = AddVertex(start);
|
|
|
+ if (startV == null)
|
|
|
+ {
|
|
|
+ throw new Exception("start不能为null");
|
|
|
+ }
|
|
|
+ var endV = AddVertex(end);
|
|
|
+ if (endV == null)
|
|
|
+ {
|
|
|
+ throw new Exception("end不能为null");
|
|
|
+ }
|
|
|
+ edge.StartVertex = startV.Id;
|
|
|
+ edge.EndVertex = endV.Id;
|
|
|
+ edge.Id = GenerateEdgeIndex();
|
|
|
+ this.m_Edges.Add(edge);
|
|
|
+ return edge;
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+ /// <summary>
|
|
|
+ /// 移除边信息
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="edgeId"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public virtual bool RemoveEdge(string edgeId)
|
|
|
+ {
|
|
|
+ return this.m_Edges.Remove(edgeId); ;
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 联动查询
|
|
|
+ /*
|
|
|
+ * 念念不忘的可优化部分;根据点去查询边的情况
|
|
|
+ */
|
|
|
+ /// <summary>
|
|
|
+ /// 获取出边
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="vertexId"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public List<E> GetOutEdges(string vertexId)
|
|
|
+ {
|
|
|
+ List<E> result = new List<E>();
|
|
|
+ foreach (var edge in this.Edges)
|
|
|
+ {
|
|
|
+ var flag = edge.ContainVertex(vertexId);
|
|
|
+ if (flag == -1)
|
|
|
+ continue;
|
|
|
+ if (!IsDirection)
|
|
|
+ {
|
|
|
+ result.Add(edge);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (flag == 0)
|
|
|
+ {
|
|
|
+ result.Add(edge);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取入边
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="vertexId"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public List<E> GetInEdges(string vertexId)
|
|
|
+ {
|
|
|
+ List<E> result = new List<E>();
|
|
|
+ foreach (var edge in this.Edges)
|
|
|
+ {
|
|
|
+ var flag = edge.ContainVertex(vertexId);
|
|
|
+ if (flag == -1)
|
|
|
+ continue;
|
|
|
+ if (!IsDirection)
|
|
|
+ {
|
|
|
+ result.Add(edge);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (flag == 1)
|
|
|
+ {
|
|
|
+ result.Add(edge);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取两个点确定的边信息
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="startId"></param>
|
|
|
+ /// <param name="endId"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public List<E> GetEdges(string startId, string endId)
|
|
|
+ {
|
|
|
+ List<E> result = new List<E>();
|
|
|
+ var edges = GetOutEdges(startId);
|
|
|
+ foreach (var edge in edges)
|
|
|
+ {
|
|
|
+ if (edge.GetAnotherVertex(startId) == endId)
|
|
|
+ {
|
|
|
+ result.Add(edge);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取出的邻节点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="vertexId"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public List<V> GetOutVertexes(string vertexId)
|
|
|
+ {
|
|
|
+ List<V> result = new List<V>();
|
|
|
+ var edges = GetOutEdges(vertexId);
|
|
|
+ foreach (var edge in edges)
|
|
|
+ {
|
|
|
+ var otherId = edge.GetAnotherVertex(vertexId);
|
|
|
+ if (this.m_Vertexes.Contains(otherId))
|
|
|
+ {
|
|
|
+ result.Add(this.m_Vertexes[otherId]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取入的邻接点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="vertexId"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public List<V> GetInVertexes(string vertexId)
|
|
|
+ {
|
|
|
+ List<V> result = new List<V>();
|
|
|
+ var edges = GetInEdges(vertexId);
|
|
|
+ foreach (var edge in edges)
|
|
|
+ {
|
|
|
+ var otherId = edge.GetAnotherVertex(vertexId);
|
|
|
+ if (this.m_Vertexes.Contains(otherId))
|
|
|
+ {
|
|
|
+ result.Add(this.m_Vertexes[otherId]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取边的开始点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="edge"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public V GetStartVertex(E edge)
|
|
|
+ {
|
|
|
+ return FindVertex(edge.StartVertex);
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取边的结束点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="edge"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public V GetEndVertex(E edge)
|
|
|
+ {
|
|
|
+ return FindVertex(edge.EndVertex);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取边的开始点的根节点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="edge"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public V GetBootStartVertex(E edge)
|
|
|
+ {
|
|
|
+ return FindVertex(edge.StartVertex)?.GetRoot() as V;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取边的结束店的根节点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="edge"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public V GetBootEndVertex(E edge)
|
|
|
+ {
|
|
|
+ return FindVertex(edge.EndVertex)?.GetRoot() as V;
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 相关公开方法
|
|
|
+ /// <summary>
|
|
|
+ /// 获取最后一个状态的边集集合
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ public static List<E> GetLastStateEdges(IEnumerable<E> inputEdges)
|
|
|
+ {
|
|
|
+ var edges = inputEdges.Where(e => e.Parent == null).ToList();
|
|
|
+ return edges;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取原始状态的边集合
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ public static List<E> GeFirstStateEdges(IEnumerable<E> inputEdges)
|
|
|
+ {
|
|
|
+ var edges = inputEdges.Where(e => e.Parent.Children.Count == 0).ToList();
|
|
|
+ return edges;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取最后一个状态的边集集合
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ public List<E> GetLastStateEdges()
|
|
|
+ {
|
|
|
+ return GetLastStateEdges(this.Edges);
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 获取原始状态的边集合
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ public List<E> GeFirstStateEdges()
|
|
|
+ {
|
|
|
+ return GeFirstStateEdges(this.Edges);
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+ }
|
|
|
+}
|