C#,图论与图算法,图(Graph)的数据结构设计与源代码

因为后面即将发布的大量有关“图”的算法与源代码都需要用到下面的这些基础数据,为避免大家去下载,特意先发布于此。

一、图(Graph)的基础知识

图(Graph)是一组对象的图示,其中一些对象对通过链接连接。互连对象由称为顶点的点表示,连接顶点的链接称为边。

形式上,图是一对集(V,E),其中V是顶点集,E是连接顶点对的边集。

图形数据结构

数学图可以用数据结构表示。我们可以使用顶点数组和二维边数组来表示图。在继续之前,让我们先熟悉一些重要的术语−

顶点− 图的每个节点都表示为一个顶点。在以下示例中,带标签的圆表示顶点。因此,A到G是顶点。我们可以使用下图所示的数组来表示它们。这里A可以通过索引0来标识。B可以使用索引1等进行识别。

− 边表示两个顶点之间的路径或两个顶点之间的线。在以下示例中,从A到B、B到C等的线表示边。我们可以使用二维数组来表示数组,如下图所示。这里AB可以表示为第0行第1列的1,BC可以表示为第1行第2列的1,依此类推,其他组合保持为0。

邻接关系− 如果两个节点或顶点通过边相互连接,则它们是相邻的。在以下示例中,B与A相邻,C与B相邻,依此类推。

路径− 路径表示两个顶点之间的边序列。

二、图的基本操作

以下是图形的基本主要操作:

添加顶点 — 将顶点添加到图形中。

添加边 — 在图形的两个顶点之间添加边。

显示顶点 — 显示图形的顶点。

遍历 — 深度优先遍历,宽度优先遍历;

布局 — 图的布局算法

三、图的相关数据

1、节点

using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;

namespace Legalsoft.Truffer.Algorithm
{
    /// <summary>
    /// 图的结点(坐标)信息
    /// </summary>
    public class Node
    {
        /// <summary>
        /// 编号
        /// </summary>
        public int Id { get; set; } = 0;
        /// <summary>
        /// X坐标
        /// </summary>
        public double X { get; set; } = 0.0;
        /// <summary>
        /// Y坐标
        /// </summary>
        public double Y { get; set; } = 0.0;
        //public int Weight { get; set; } = 0;
        /// <summary>
        /// 默认构造函数
        /// </summary>
        public Node() 
		{
		}

		public Node(int id) 
		{
			Id = id;
		}

        /// <summary>
        /// 长度(原点距离)
        /// </summary>
        public double Length
        {
            get
            {
                double len = LengthSquare;
                if (Math.Abs(len) < float.Epsilon) return 0.0;
                return Math.Sqrt(len);
            }
        }

        /// <summary>
        /// 长度平方
        /// </summary>
        public double LengthSquare
        {
            get
            {
                return (X * X) + (Y * Y);
            }
        }

        /// <summary>
        /// 缩放
        /// </summary>
        /// <param name="rate"></param>
        public void Scale(double rate)
        {
            X *= rate;
            Y *= rate;
        }

        /// <summary>
        /// 移动到目的点
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public void MoveTo(double x, double y)
        {
            X = x;
            Y = y;
        }

        /// <summary>
        /// 移动
        /// </summary>
        /// <param name="delta"></param>
        public void Move(Node delta)
        {
            this.X += delta.X;
            this.Y += delta.Y;
        }

        /// <summary>
        /// 加号重载
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static Node operator +(Node a, Node b)
        {
            Node c = new Node();
            c.X = a.X + b.X;
            c.Y = a.Y + b.Y;
            return c;
        }

        /// <summary>
        /// 减号重载
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static Node operator -(Node a, Node b)
        {
            Node c = new Node();
            c.X = a.X - b.X;
            c.Y = a.Y - b.Y;
            return c;
        }
    }
}

2、边

using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;

namespace Legalsoft.Truffer.Algorithm
{
	public class Edge
	{
		/// <summary>
		/// 起点(第一点)编号
		/// </summary>
		public int First { get; set; } = -1;
		/// <summary>
		/// 终点(第二点)编号
		/// </summary>
		public int Second { get; set; } = -1;
		/// <summary>
		/// 权值
		/// </summary>
		public int Weight { get; set; } = 0;
		/// <summary>
		/// 默认构造函数
		/// </summary>
		public Edge()
		{
		}
		/// <summary>
		/// 两点构造函数
		/// </summary>
		/// <param name="f"></param>
		/// <param name="s"></param>
		public Edge(int f, int s)
		{
			First = f;
			Second = s;
		}
		/// <summary>
		/// 两点及权值构造函数
		/// </summary>
		/// <param name="f"></param>
		/// <param name="s"></param>
		/// <param name="w"></param>
		public Edge(int f, int s, int w)
		{
			First = f;
			Second = s;
			Weight = w;
		}
	}
}

3、图

using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;

namespace Legalsoft.Truffer.Algorithm
{
	public partial class Graph
	{
		/// <summary>
		/// 是否为有向图?
		/// </summary>
		public bool Direction { get; set; } = false;
		/*
		/// <summary>
		/// 节点编码的起始编号0或1
		/// </summary>
		public int Node_Index_Start { get; set; } = 0;
		/// <summary>
		/// 节点编码的结束编号
		/// </summary>
		public int Node_Index_End { get; set; } = 0;
		*/
		/// <summary>
		/// 节点总数
		/// </summary>
		public int Node_Number { get; set; } = 0;
		/*
		/// <summary>
		/// 连线编码的起始编号0或1
		/// </summary>
		public int Edge_Start { get; set; } = 0;
		*/
		/// <summary>
		/// 连接线总数
		/// </summary>
		public int Edge_Number { get; set; } = 0;
		/// <summary>
		/// 节点编码列表
		/// </summary>
		public List<Node> Nodes { get; set; } = new List<Node>();
		/// <summary>
		/// 连接线列表
		/// </summary>
		public List<Edge> Edges { get; set; } = new List<Edge>();
		/// <summary>
		/// 节点邻接表
		/// </summary>
		public List<int>[] Adjacency { get; set; } = null;
		/// <summary>
		/// 邻接矩阵
		/// </summary>
		public int[,] Matrix { get; set; } = null;

		public Graph()
		{
		}

		public Graph(int v, int e = 0, bool direct = false)
		{
			Direction = direct;
			Node_Number = v;
			Edge_Number = e;
			Adjacency = new List<int>[Node_Number + 1];
			for (int i = 0; i <= Node_Number; i++)
			{
				Adjacency[i] = new List<int>();
			}
		}

		public void AddEdge(int a, int b)
		{
			Adjacency[a].Add(b);
			if (Direction == false)
			{
				Adjacency[b].Add(a);
			}
		}

		public void AddEdge(int a, int b, int w)
		{
			AddEdge(a, b);
			Edges.Add(new Edge(a, b, w));
		}

		public void AddEdge(int idx, int a, int b, int w)
		{
			Edges[idx] = new Edge(a, b, w);
		}

		public void AddNode(int a)
		{
			if (!Nodes.Exists(t => t.Id == a))
			{
				Nodes.Add(new Node(a));
			}
		}

		/// <summary>
		/// 按三元组构造图数据
		/// 三元数组为: {source,destination,weight}
		/// </summary>
		/// <param name="ternary_array">三元数据</param>
		public Graph(int[,] ternary_array, bool dir = false)
		{
			// 有向图?无向图?
			Direction = dir;

			Nodes = new List<Node>();
			Edges = new List<Edge>();
			Edge_Number = ternary_array.GetLength(0);
			for (int i = 0; i < ternary_array.GetLength(0); i++)
			{
				int n1 = ternary_array[i, 0];
				int n2 = ternary_array[i, 1];
				int wt = ternary_array[i, 2];
				AddEdge(n1, n2, wt);
			}
		}

		/// <summary>
		/// 按关联矩阵数据构建图
		/// [N x N],元素=0,无连接,>0 有连接线及weight
		/// </summary>
		/// <param name="v">节点数</param>
		/// <param name="e">连边数</param>
		/// <param name="matrix">关联矩阵</param>
		public Graph(int[,] matrix)
		{
			Node_Number = matrix.GetLength(0);
			Nodes = new List<Node>();
			Edges = new List<Edge>();
			Matrix = new int[Node_Number, Node_Number];
			for (int i = 0; i < Node_Number; i++)
			{
				for (int j = 0; j < Node_Number; j++)
				{
					if (matrix[i, j] > 0)
					{
						AddEdge(i, j, matrix[i, j]);
						Matrix[i, j] = matrix[i, j];
					}
				}
			}
		}

		public Edge FindEdge(int a, int b)
        {
			foreach (Edge e in Edges)
			{
				if (e.First == a && e.Second == b)
				{
					return e;
				}
				if (Direction == false)
				{
					if (e.First == b && e.Second == a)
					{
						return e;
					}
				}
			}
			return null;
        }

		/// <summary>
		/// 按邻接表的构造函数
		/// </summary>
		/// <param name="adj"></param>
		public Graph(List<List<int>> adj, bool dir = false)
		{
			// 有向图?无向图?
			Direction = dir;

			Node_Number = adj.Count;
			Nodes = new List<Node>();
			Edges = new List<Edge>();

			// 邻接矩阵
			Adjacency = adj.ToArray();

			int idx = 1;
			foreach (List<int> xu in adj)
			{
				foreach (int xv in xu)
				{
					AddEdge(idx, xv);
				}
				idx++;
			}
		}

		/// <summary>
		/// 邻接表 转为 邻接矩阵
		/// 1 起步!
		/// </summary>
		/// <returns></returns>
		public int[,] AdjacencyMatrix()
		{
			if (Matrix == null)
			{
				Matrix = new int[Node_Number + 1, Node_Number + 1];
				int idx = 0;
				foreach (List<int> xu in Adjacency)
				{
					// 因为 Adjacency[0] 没有被使用!跳过!
					if (idx > 0)
					{
						foreach (int xv in xu)
						{
							Matrix[idx, xv] = 1;
						}
					}
					idx++;
				}
			}
			return Matrix;
		}
	}
}

POWER BY TRUFFER.CN