1 图的表示
2. 有向图的遍历算法:深度优先
3. 有向图的遍历算法:广度优先
4 代码反思
5. 下载
1. 图的表示
1.1 图的定义
图G定义为V和E的集合G={V, E},其中V表示图中的所有的顶点集合,E表示的是G中的所有的边的集合。图按照E中的元素是否有方向,分为有向图和无向图。
1.2 图的表示方法
上面给出的数学上图的定义,那么在计算机中如何表示图?通常意义上,有下面的两种方法:邻接表和邻接矩阵表示法。
无向图的邻接表和邻接矩阵表示如下所示:
有向图的邻接表和邻接矩阵表示如下所示:
根据上面的表示方法,下面定义图G的这种数据结构(邻接表),首先定义图的顶点GraphVertex:
// 顶点显示的符号 public char Symbol { get; set; } // 顶点当前颜色 public VertexColor Color { get; set; } // 顶点和开始节点之间的距离 public int Distance { get; set; } // 广度遍历父节点 public GraphVertex Parent { get; set; } // 深度优先搜索中的开始时间 public int StartTime { get; set; } // 深度优先搜索中的结束时间 public int FinishTime { get; set; } // 顶点对应的边
public List<GraphEdge> FollowEdges { get; set; }
定义图G的边的数据结构:
// 边开始顶点,在邻接表的存储中其实没有必要存储 public GraphVertex From { get; set; } // 结束顶点 public GraphVertex To { get; set; } // 边权重
public int Weight { get; set; }
定义图:
// 数据成员,这里假设的是顶点的symbol是各个不相同的 private Hashtable graph = new Hashtable();
private int time = 0;
整体上的结构如下:
2. 有向图的深度优先算法
2.1 基本算法
其中d表明的是某个节点第一次被发现的时间点,f表明从节点出发的全部节点已经被发现的时间。
2.2 设计实现
// 深度优先遍历算法 public void DepthFirstVisit(GraphVertex v) { // 刚刚被发现,颜色为gray Console.WriteLine(v.Symbol); v.Color = VertexColor.GRAY; this.time++; // 开始时间 v.StartTime = this.time; foreach (GraphEdge edge in v.FollowEdges) { // 还未被发现 if (edge.To.Color == VertexColor.WHITE) { edge.To.Parent = v; DepthFirstVisit(edge.To); } } // 如果边都已经发现完成 v.Color = VertexColor.BLACK; this.time++; v.FinishTime = this.time; } public void DepthFirstTravel() { // 全局时间变量 this.time = 0; // 初始化 GraphVertex v; foreach (DictionaryEntry e in this.graph) { v = (GraphVertex)e.Value; v.Color = VertexColor.WHITE; v.Parent = null; } // 递归调用 // 队所有的顶点 foreach (DictionaryEntry e in this.graph) { v = (GraphVertex)e.Value; // 顶点为白色 if (v.Color == VertexColor.WHITE) { DepthFirstVisit(v); } }
}
3. 有向图的遍历算法:广度优先
3.1 基本算法
其中color域表示的是当前某个节点被发现的状态。如果是white表明没有被发现,gray表示当前顶点已经被发现,但是从该节点出发的节点还没有被全部发现。parent域定义的是在搜索算法时父节点。distance域表明的是从节点s到某个发现的节点v的路径距离。
3.2 设计实现
// 广度优先遍历算法,同时生成广度优先树 public void BreadthFirstTravel(GraphVertex s) { // 初始化所有节点 GraphVertex v; foreach (DictionaryEntry e in this.graph) { v = (GraphVertex)e.Value; v.Color = VertexColor.WHITE; v.Distance = int.MaxValue; v.Parent = null; } // 发现第一个节点 s.Color = VertexColor.GRAY; s.Distance = 0; s.Parent = null; // 初始化队列 Queue context = new Queue(); context.Enqueue(s); // 如果队列不空的话 while (context.Count != 0) { // 队首元素出队 v = context.Dequeue() as GraphVertex; Console.WriteLine(v.Symbol); // 遍历v的节点 foreach (GraphEdge item in v.FollowEdges) { if ( item.To.Color == VertexColor.WHITE) { item.To.Color = VertexColor.GRAY; item.To.Distance = v.Distance + 1; item.To.Parent = v; context.Enqueue(item.To); } } v.Color = VertexColor.BLACK; }
}
4. 代码反思
上面的搜索代码结构是比较典型的搜索结构:首先定义队列或者是栈来保存程序运行状态,如果容器不空,取出元素,然后对取出的元素做一些处理。