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. 代码反思
上面的搜索代码结构是比较典型的搜索结构:首先定义队列或者是栈来保存程序运行状态,如果容器不空,取出元素,然后对取出的元素做一些处理。
5. 代码下载
/Files/xuqiang/DirectedGraph1.rar