算法:图(Graph)的遍历、最小生成树和拓扑排序
2013-12-27 10:27
323 查看
背景
不同的数据结构有不同的用途,像:数组、链表、队列、栈多数是用来做为基本的工具使用,二叉树多用来作为已排序元素列表的存储,B 树用在存储中,本文介绍的 Graph 多数是为了解决现实问题(说到底,所有的数据结构都是这个目的),如:网络布局、任务安排等。图的基本概念
示例using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataStuctureStudy.Graphs { class GraphTest { public static void Test() { var graph = new Graph<String>(50); graph .AddVertex("A") .AddVertex("B") .AddVertex("C") .AddVertex("D") .AddVertex("E") .AddVertex("F") .AddVertex("G") .AddVertex("H") .AddVertex("I"); graph .AddDirectedEdge("A", "B").AddDirectedEdge("A", "C").AddDirectedEdge("A", "D").AddDirectedEdge("A", "E") .AddDirectedEdge("B", "F") .AddDirectedEdge("D", "G") .AddDirectedEdge("F", "H") .AddDirectedEdge("G", "I"); Console.WriteLine("深度遍历,栈版本:"); graph.DepthFirstSearch("A", Console.Write); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("深度遍历,递归版本:"); graph.DepthFirstSearchRecursion("A", Console.Write); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("广度遍历:"); graph.BreadthFirstSearch("A", Console.Write); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("最小生成树:"); graph.DisplayMinimumSpanningTree("A"); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("拓扑排序:"); var results = graph.TopologySort(); Console.WriteLine(String.Join("->", results.ToArray())); Console.WriteLine(); } class Vertex<T> { public T Value { get; set; } public bool WasVisited { get; set; } } class Graph<T> { #region 私有字段 private int _maxSize; private Vertex<T>[] _vertexs; private bool[][] _edges; private int _vertexCount = 0; #endregion #region 构造方法 public Graph(int maxSize) { _maxSize = maxSize; _vertexs = new Vertex<T>[_maxSize]; _edges = new bool[_maxSize][]; for (var i = 0; i < _maxSize; i++) { _edges[i] = new bool[_maxSize]; } } #endregion #region 添加顶点 public Graph<T> AddVertex(T value) { _vertexs[_vertexCount++] = new Vertex<T> { Value = value }; return this; } #endregion #region 添加边 public Graph<T> AddUnDirectedEdge(T startItem, T endItem) { var startIndex = this.GetVertexIndex(startItem); var endIndex = this.GetVertexIndex(endItem); _edges[startIndex][endIndex] = true; _edges[endIndex][startIndex] = true; return this; } public Graph<T> AddDirectedEdge(T startItem, T endItem) { var startIndex = this.GetVertexIndex(startItem); var endIndex = this.GetVertexIndex(endItem); _edges[startIndex][endIndex] = true; return this; } #endregion #region 深度优先遍历:栈版本 public void DepthFirstSearch(T startItem, Action<T> action) { var startIndex = this.GetVertexIndex(startItem); var stack = new Stack<int>(); this.DepthFirstSearchVisit(stack, startIndex, action); while (stack.Count > 0) { var adjoinVertexIndex = this.GetNextUnVisitedAdjoinVertexIndex(stack.Peek()); if (adjoinVertexIndex >= 0) { this.DepthFirstSearchVisit(stack, adjoinVertexIndex, action); } else { stack.Pop(); } } this.ResetVisited(); } private void DepthFirstSearchVisit(Stack<int> stack, int index, Action<T> action) { _vertexs[index].WasVisited = true; action(_vertexs[index].Value); stack.Push(index); } #endregion #region 深度优先遍历:递归版本 public void DepthFirstSearchRecursion(T startItem, Action<T> action) { var startIndex = this.GetVertexIndex(startItem); this.DepthFirstSearchRecursionVisit(startIndex, action); this.ResetVisited(); } private void DepthFirstSearchRecursionVisit(int index, Action<T> action) { _vertexs[index].WasVisited = true; action(_vertexs[index].Value); var adjoinVertexIndex = this.GetNextUnVisitedAdjoinVertexIndex(index); while (adjoinVertexIndex >= 0) { this.DepthFirstSearchRecursionVisit(adjoinVertexIndex, action); adjoinVertexIndex = this.GetNextUnVisitedAdjoinVertexIndex(index); } } #endregion #region 广度优先遍历 public void BreadthFirstSearch(T startItem, Action<T> action) { var startIndex = this.GetVertexIndex(startItem); var queue = new Queue<int>(); this.BreadthFirstSearchVisit(queue, startIndex, action); while (queue.Count > 0) { var adjoinVertexIndexs = this.GetNextUnVisitedAdjoinVertexIndexs(queue.Dequeue()); foreach (var adjoinVertexIndex in adjoinVertexIndexs) { this.BreadthFirstSearchVisit(queue, adjoinVertexIndex, action); } } this.ResetVisited(); } private void BreadthFirstSearchVisit(Queue<int> queue, int index, Action<T> action) { _vertexs[index].WasVisited = true; action(_vertexs[index].Value); queue.Enqueue(index); } #endregion #region 最小生成树 public void DisplayMinimumSpanningTree(T startItem) { var startIndex = this.GetVertexIndex(startItem); var queue = new Queue<int>(); _vertexs[startIndex].WasVisited = true; queue.Enqueue(startIndex); while (queue.Count > 0) { var currentIndex = queue.Dequeue(); var adjoinVertexIndexs = this.GetNextUnVisitedAdjoinVertexIndexs(currentIndex); foreach (var adjoinVertexIndex in adjoinVertexIndexs) { Console.WriteLine(_vertexs[currentIndex].Value + "->" + _vertexs[adjoinVertexIndex].Value); _vertexs[adjoinVertexIndex].WasVisited = true; queue.Enqueue(adjoinVertexIndex); } } this.ResetVisited(); } #endregion #region 拓扑排序 public List<T> TopologySort() { var cloneVertexs = (Vertex<T>[])_vertexs.Clone(); var cloneEdges = (bool[][])_edges.Clone(); var cloneVertexCount = _vertexCount; var results = new List<T>(); while (_vertexCount > 0) { var successor = this.NextSuccessor(); if (successor == -1) { throw new InvalidOperationException("出现循环了!"); } results.Insert(0, _vertexs[successor].Value); this.RemoveVertex(successor); _vertexCount--; } _vertexs = cloneVertexs; _edges = cloneEdges; _vertexCount = cloneVertexCount; return results; } private int NextSuccessor() { for (var row = 0; row < _vertexCount; row++) { if (_edges[row].Take(_vertexCount).All(x => !x)) { return row; } } return -1; } private void RemoveVertex(int successor) { for (int i = successor; i < _vertexCount - 1; i++) { _vertexs[i] = _vertexs[i + 1]; } for (int row = successor; row < _vertexCount - 1; row++) { for (int column = 0; column < _vertexCount; column++) { _edges[row][column] = _edges[row + 1][column]; } } for (int column = successor; column < _vertexCount - 1; column++) { for (int row = 0; row < _vertexCount; row++) { _edges[row][column] = _edges[row][column + 1]; } } } #endregion #region 帮助方法 private int GetVertexIndex(T item) { for (var i = 0; i < _vertexCount; i++) { if (_vertexs[i].Value.Equals(item)) { return i; } } return -1; } private int GetNextUnVisitedAdjoinVertexIndex(int index) { for (var i = 0; i < _vertexCount; i++) { if (_edges[index][i] && _vertexs[i].WasVisited == false) { return i; } } return -1; } private List<int> GetNextUnVisitedAdjoinVertexIndexs(int index) { var results = new List<int>(); for (var i = 0; i < _vertexCount; i++) { if (_edges[index][i] && _vertexs[i].WasVisited == false) { results.Add(i); } } return results; } private void ResetVisited() { for (var i = 0; i < _vertexCount; i++) { _vertexs[i].WasVisited = false; } } #endregion } } }
View Code
备注
本文没有解释权重图,下篇再介绍。相关文章推荐
- 图(有向图)的邻接表表示 C++实现(遍历,拓扑排序,最短路径,最小生成树) Implement of digraph and undigraph using adjacency list
- Graph的算法实现: 寻找一幅图的最小生成树(MST)
- 数据结构:图——图的遍历、最小生成树、最短路径算法
- 数据结构:图的存储、图的遍历、最小生成树、最短路径、拓扑排序
- 数据结构 学习笔记(九):图(下):最小生成树(Prim,Kruskal 算法),拓扑排序 AOV,关键路径 AOE
- 图的遍历(dfs、bfs、最短路、最小生成树、拓扑排序)
- 数据结构实验报告-图算法-最小生成树-最短路-拓扑排序-搜索
- 图(有向图,无向图)的邻接矩阵表示C++实现(遍历,拓扑排序,最短路径,最小生成树) Implement of digraph and undigraph using adjacency matrix
- [数据结构]--图(图的遍历,最小生成树,最短路径算法)
- 拓扑排序 详解+最小生成树(MST)详解 【普利姆算法 + 优先队列优化 & 克鲁斯卡尔算法】
- 图基本算法:深度广度遍历最小生成树
- 拓扑排序 详解 + 并查集 详解 + 最小生成树(MST)详解 【普利姆算法 + 优先队列优化 & 克鲁斯卡尔算法】
- 无向图基本算法 -- 遍历及最小生成树算法
- 无向图基本算法 -- 遍历及最小生成树算法
- 拓扑排序 详解 + 并查集 详解 + 最小生成树(MST)详解 【普利姆算法 + 优先队列优化 & 克鲁斯卡尔算法】
- 图的广度遍历、深度遍历及最小生成树书算法(Prim、Kruskal)
- 最小生成树算法(一)--对prim算法的理解
- 最小生成树(普利姆算法、克鲁斯卡尔算法) .
- 算法提高 最小方差生成树
- 图解最小生成树 - 普里姆(Prim)算法