您的位置:首页 > 其它

算法:图(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

备注

本文没有解释权重图,下篇再介绍。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐