python中判断无向图是否有环_每天5分钟用C#学习数据结构(21)图 Part 2

3720c724b9457711057f3007d3fd9ecb.png 【基础知识作者 / Edison Zhou 这是 恰童鞋骚年 的第 217 篇原创文章
上一篇介绍了图的基本知识及存储结构,由于邻接矩阵容易造成空间资源的浪费,这一篇我们主要来动手实现一个基于邻接表结构的图。 1总体结构实现

(1)链表节点定义

① 表头节点Vertex

/// /// 嵌套类:存放于数组中的表头节点/// /// protected class Vertex<TValue>{    public TValue data;     // 数据    public Node firstEdge;  // 邻接点链表头指针    public bool isVisited;  // 访问标志:遍历时使用    public Vertex()    {        this.data = default(TValue);    }    public Vertex(TValue value)    {        this.data = value;    }}

② 表节点Node

/// /// 嵌套类:链表中的表节点/// protected class Node{    public Vertex adjvex;    // 邻接点域    public Node next;           // 下一个邻接点指针域    public Node()    {        this.adjvex = null;    }    public Node(Vertexvalue)    {        this.adjvex = value;    }}

(2)邻接表总体定义

public class MyAdjacencyListwhere T : class{    private List>> items;      public MyAdjacencyList()        : this(10)    {    }    public MyAdjacencyList(int capacity)    {        this.items = new List>>(capacity);    }        #region 基本方法:为图中添加顶点、添加有向与无向边    #endregion        #region 辅助方法:图中是否包含某个元素、查找指定顶点、初始化visited标志    #endregion            #region 嵌套类:表头节点与表节点定义    #endregion}

首先,我们使用了一个动态集合List来代替数组存储Vertex的集合,默认容量为10,且不需要数组存储空间不够的情况,简化了操作。其次,我们要定义一些基本方法,如添加顶点、添加边。还要定义一些辅助方法,如判断是否包含某个元素等(详见完整代码文件)。最后,我们再实现图的一些遍历算法,如深度优先遍历与广度优先遍历(本篇不作介绍,下一篇再介绍)。

2基本方法代码实现

(1)添加一个顶点

这里其实就是往集合里边加入新元素:

/// /// 添加一个顶点/// /// 顶点元素datapublic void AddVertex(T item){    if (Contains(item))    {        throw new ArgumentException("添加了重复的顶点!");    }    Vertex newVertex = new Vertex(item);    items.Add(newVertex);}

(2)添加一条边

这里需要分为两种情况,一种是添加无向图的边,这时无向图的两个顶点都需要记录边的信息。另一种则是添加有向图的边,这时只需要一条记录。

① 无向图

/// /// 添加一条无向边/// /// 头顶点data/// 尾顶点data/// 权值public void AddEdge(T from, T to){    Vertex fromVertex = Find(from);    if (fromVertex == null)    {        throw new ArgumentException("头顶点不存在!");    }    Vertex toVertex = Find(to);    if (toVertex == null)    {        throw new ArgumentException("尾顶点不存在!");    }    // 无向图的两个顶点都需要记录边的信息    AddDirectedEdge(fromVertex, toVertex);    AddDirectedEdge(toVertex, fromVertex);}

这里可以看到这两句代码,对应的两个顶点都记录了边的信息。

// 无向图的两个顶点都需要记录边的信息AddDirectedEdge(fromVertex, toVertex);AddDirectedEdge(toVertex, fromVertex);

② 有向图

/// /// 添加一条有向边/// /// 头结点data/// 尾节点datapublic void AddDirectedEdge(T from, T to){    Vertex fromVertex = Find(from);    if (fromVertex == null)    {        throw new ArgumentException("头顶点不存在!");    }    Vertex toVertex = Find(to);    if (toVertex == null)    {        throw new ArgumentException("尾顶点不存在!");    }    AddDirectedEdge(fromVertex, toVertex);}

③ 如何添加边

在实现中,无论是无线图还是有向图都是添加的有向边,只不过无向图是添加了两条有向边:

/// /// 添加一条有向边/// /// 头顶点/// 尾顶点private void AddDirectedEdge(Vertex fromVertex, Vertex toVertex){    if (fromVertex.firstEdge == null)    {        fromVertex.firstEdge = new Node(toVertex);    }    else    {        Node temp = null;        Node node = fromVertex.firstEdge;        do        {            // 检查是否添加了重复边            if (node.adjvex.data.Equals(toVertex.data))            {                throw new ArgumentException("添加了重复的边!");            }            temp = node;            node = node.next;        } while (node != null);        Node newNode = new Node(toVertex);        temp.next = newNode;    }}

(3)打印每个顶点及其邻接点的信息

/// /// 打印打印每个顶点和它的邻接点/// /// 是否是有向图public string GetGraphInfo(bool isDirectedGraph = false){    StringBuilder sb = new StringBuilder();    foreach (Vertex v in items)    {        sb.Append(v.data.ToString() + ":");        if (v.firstEdge != null)        {            Node temp = v.firstEdge;            while (temp != null)            {                if (isDirectedGraph)                {                    sb.Append(v.data.ToString() + "→" + temp.adjvex.data.ToString() + " ");                }                else                {                    sb.Append(temp.adjvex.data.ToString());                }                temp = temp.next;            }        }        sb.Append("\r\n");    }    return sb.ToString();}

这里判断了是否是有向图,如果是有向图则显示A→B的形式,如果是无向图则显示A:B的形式。

3基本功能测试

4f32ef8ed38892a895cc2a6c72b28c0f.png

3d29915f4889ed9842ac1b883679945a.png

这里我们对基本功能做一下测试,分为无向图和有向图,首先插入顶点及对应边,然后打印顶点及其邻接表的信息,要构造的无向图与有向图如上面两张图所示,测试代码如下所示:

static void MyAdjacencyListTest(){    Console.WriteLine("------------无向图------------");    MyAdjacencyList<string> adjList = new MyAdjacencyList<string>();    // 添加顶点    adjList.AddVertex("A");    adjList.AddVertex("B");    adjList.AddVertex("C");    adjList.AddVertex("D");    //adjList.AddVertex("D"); // 会报异常:添加了重复的节点    // 添加无向边    adjList.AddEdge("A", "B");    adjList.AddEdge("A", "C");    adjList.AddEdge("A", "D");    adjList.AddEdge("B", "D");    //adjList.AddEdge("B", "D"); // 会报异常:添加了重复的边    Console.Write(adjList.GetGraphInfo());    Console.WriteLine("------------有向图------------");    MyAdjacencyList<string> dirAdjList = new MyAdjacencyList<string>();    // 添加顶点    dirAdjList.AddVertex("A");    dirAdjList.AddVertex("B");    dirAdjList.AddVertex("C");    dirAdjList.AddVertex("D");    // 添加有向边    dirAdjList.AddDirectedEdge("A", "B");    dirAdjList.AddDirectedEdge("A", "C");    dirAdjList.AddDirectedEdge("A", "D");    dirAdjList.AddDirectedEdge("B", "D");    Console.Write(dirAdjList.GetGraphInfo(true));}

运行结果如下图所示:

ddd86997490fdd5fb8087571418c524e.png

4小结

由于邻接矩阵容易造成空间资源的浪费,本篇欧中介绍了用C#代码来实现图的邻接矩阵结构实现。下一篇,我们会用C#代码来实现图的遍历算法。

5参考资料 程杰,《大话数据结构》 陈广,《数据结构(C#语言描述)》 段恩泽,《数据结构(C#语言版)》 往期 精彩 回顾

每天5分钟用C#学习数据结构(20)

4af7a4db627a34e39b7bb649f6753476.png 如果本文对你有用, 不妨点个“在看”或者转发朋友圈

5fe776ff6e1159f930f89fbaf9b90ed2.png

👇点击

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值