17 图

知识结构:

图1 知识结构

1. 图的基本概念与术语

1.1 图的定义

图由顶点集和边集组成,记为 。

  • 顶点集:顶点的有穷非空集合,记为。
  • 边集:顶点偶对的有穷集合,记为 。

边:

  • 无向边:
  • 有向边(弧): 始点称为弧尾,终点称为弧头。

例题:

图2 图的表示

例题:

图3 图的表示

1.2 图的分类

  • 有向图:由有向边构成。
  • 无向图:由无向边构成。

1.3 图中顶点数与边数的关系

(1)设顶点数为,边数为则:

  • 无向图:,的图称为无向完全图。
  • 有向图:,的图称为有向完全图。

(2)顶点的度

  • 无向图:与连接的边数。
  • 有向图:
    • :以为终点(弧头)的边数。
    • :以为起点(弧尾)的边数。

(3)度与边的关系

(4)正则图:所有顶点的度都相同的图

图4 正则图

1.4 路径

(1)定义:图,若存在一个顶点序列 ,使得(无向图)或者(有向图)则称到存在一条路径。

(2)路径的长度:路径上边的数目。

(3)简单路径:若一条路径上除,可相同外,其余顶点均不相同的路径。

(4)简单回路:与相同的简单路径。

1.5 子图

设是一个图,若,且中的边所关联的顶点,则 也是一个图,并称其为的子图。

图5 图与子图

1.6 连通图与连通分量(无向图)

连通图:无向图的中,任何两个顶点都存在路径,则称为连通图。

连通分量:无向图的极大连通子图。

注:

  • 连通图的连通分量只有一个,为其本身。
  • 非连通图的连通分量不唯一。

例子:

图6 连通图与连通分量

1.7 强连通图与强连通分量(有向图)

强连通图:有向图的中,任何两个顶点都存在路径,则称为强连通图。

强连通分量:有向图的极大连通子图。

注:

  • 强连通图的强连通分量只有一个,为其本身。
  • 非强连通图的强连通分量不唯一。

例子:

图7 强连通图与强联通分量

1.8 网络

中的每条边都带有权值的图称为网络。

注:权一般具有实际意义,比如距离、消耗等。

例子:

图8 网络

2. 图的存储结构

2.1 顺序存储(邻接矩阵)

邻接矩阵:表示顶点之间相邻关系的矩阵

若图,则其邻接矩阵可表示为:

例子:无向图的存储

图9 邻接矩阵存储无向图

例子:有向图的存储

图10 邻接矩阵存储有向图

若图为网络,则其邻接矩阵可表示为:

例子:网络的存储

图11 邻接矩阵存储网络

图12 MGraph结构
using System;namespace NonLinearStruct.Graph{    ///     /// 图抽象数据类型实现--利用邻接矩阵    ///     public class MGraph    {        private readonly double[,] _adMatrix;//邻接矩阵        private readonly string[] _vertexNameList;//存储图中各结点名字的数组

        ///         /// 获取图中结点的个数        ///         public int VertexCount { get; }

        ///         /// 初始化MGraph类的新实例        ///         /// 图中结点的个数        public MGraph(int vCount){            if (vCount <= 0)                throw new ArgumentOutOfRangeException();

            VertexCount = vCount;            _vertexNameList = new string[vCount];            _adMatrix = new double[vCount, vCount];        }

        ///         /// 获取或设置图中各结点的名称        ///         /// 结点名称从零开始的索引        /// 指定索引处结点的名称        public string this[int index]        {            get            {                if (index 0 || index > VertexCount - 1)                    throw new IndexOutOfRangeException();                return _vertexNameList[index];            }            set            {                if (index 0 || index > VertexCount - 1)                    throw new IndexOutOfRangeException();                _vertexNameList[index] = value;            }        }

        private int GetIndex(string vertexName){            //根据结点名字获取结点在数组中的下标            int i;            for (i = 0; i             {                if (_vertexNameList[i] == vertexName)                    break;            }            return i == VertexCount ? -1 : i;        }

        ///         /// 给邻接矩阵赋值        ///         /// 起始结点的名字        /// 终止结点的名字        /// 边上的权值或连接关系        public void AddEdge(string startVertexName, string endVertexName, double weight = 1){            int i = GetIndex(startVertexName);            int j = GetIndex(endVertexName);            if (i == -1 || j == -1)                throw new Exception("图中不存在该边.");            _adMatrix[i, j] = weight;        }    }}

2.2 链式存储(邻接表)

邻接表:由顺序存储的顶点表和链式存储的边表构成的图的存储结构。

例子:无向图的存储

图13 无向图的存储

例子:有向图的存储

图14 有向图的存储

例子:网络的存储

图15 网络的存储

边表结点的实现:

图16 边表结点结构

图17 EdgeNode结构
using System;namespace NonLinearStruct.Graph{    ///     /// 邻接表边表上的结点    ///     public class EdgeNode    {        ///         /// 获取边终点在顶点数组中的位置        ///         public int Index { get; }

        ///         /// 获取边上的权值        ///         public double Weight { get; }

        ///         /// 获取或设置下一个邻接点        ///         public EdgeNode Next { get; set; }

        ///         /// 初始化EdgeNode类的新实例        ///         /// 边终点在顶点数组中的位置        /// 边上的权值        /// 下一个邻接点        public EdgeNode(int index, double weight = 0.0, EdgeNode next = null){            if (index 0)                throw new ArgumentOutOfRangeException();

            Index = index;            Weight = weight;            Next = next;        }    }}

顶点表结点的实现:

图18 顶点表结点结构

图19 VertextNode结构
namespace NonLinearStruct.Graph{    ///     /// 邻接表顶点表中的结点    ///     public class VertexNode    {        ///         /// 获取或设置顶点的名字        ///         public string VertexName { get; set; }

        ///         /// 获取或设置顶点是否被访问        ///         public bool Visited { get; set; }

        ///         /// 获取或设置顶点的第一个邻接点        ///         public EdgeNode FirstNode { get; set; }

        ///         /// 初始化VertexNode类的新实例        ///         /// 顶点的名字        /// 顶点的第一个邻接点        public VertexNode(string vName, EdgeNode firstNode = null){            VertexName = vName;            Visited = false;            FirstNode = firstNode;        }    }}

图结构的实现

图20 AdGraph结构
using System;using System.Collections.Generic;using System.Linq;using LinearStruct;

namespace NonLinearStruct.Graph{    ///     /// 图抽象数据类型实现--利用邻接表    ///     public class AdGraph    {        private readonly VertexNode[] _vertexList; //结点表

        ///         /// 获取图的结点数        ///         public int VertexCount { get; }

        ///         /// 初始化AdGraph类的新实例        ///         /// 图中结点的个数        public AdGraph(int vCount){            if (vCount <= 0)                throw new ArgumentOutOfRangeException();

            VertexCount = vCount;            _vertexList = new VertexNode[vCount];        }

        ///         /// 获取或设置图中各结点的名称        ///         /// 结点名称从零开始的索引        /// 指定索引处结点的名称        public string this[int index]        {            get            {                if (index 0 || index > VertexCount - 1)                    throw new ArgumentOutOfRangeException();

                return _vertexList[index] == null                    ? "NULL"                    : _vertexList[index].VertexName;            }            set            {                if (index 0 || index > VertexCount - 1)                    throw new ArgumentOutOfRangeException();

                if (_vertexList[index] == null)                    _vertexList[index] = new VertexNode(value);                else                    _vertexList[index].VertexName = value;            }        }

        ///         /// 得到结点在结点表中的位置        ///         /// 结点的名称        /// 结点的位置        private int GetIndex(string vertexName){            int i;            for (i = 0; i             {                if (_vertexList[i] != null && _vertexList[i].VertexName == vertexName)                    break;            }            return i == VertexCount ? -1 : i;        }

        ///         /// 给图加边        ///         /// 起始结点的名字        /// 终止结点的名字        /// 边上的权值        public void AddEdge(string startVertexName, string endVertexName, double weight = 0.0){            int i = GetIndex(startVertexName);            int j = GetIndex(endVertexName);

            if (i == -1 || j == -1)                throw new Exception("图中不存在该边.");

            EdgeNode temp = _vertexList[i].FirstNode;            if (temp == null)            {                _vertexList[i].FirstNode = new EdgeNode(j, weight);            }            else            {                while (temp.Next != null)                    temp = temp.Next;                temp.Next = new EdgeNode(j, weight);            }        }    }}

3. 图的遍历

3.1 深度优先搜索

算法:

假设以为起点(源点)进行搜索。

首先标识为已访问结点,接着寻找与相邻的结点,若是未被访问结点,则以为起点进行深度优先搜索,若是已被访问结点,则寻找其它与相邻的结点,直到与有路径相通的所有结点都被访问过。

例子:

图21 图的结构

深度优先搜索的序列为:

虽然遍历序列不唯一,但是邻接表确定后,遍历序列就唯一了。

实现:

图22 AdGraph结构
private void Dfs(int i, ref string dfsResult){    //深度优先搜索递归函数    _vertexList[i].Visited = true;    dfsResult += _vertexList[i].VertexName + "\n";

    EdgeNode p = _vertexList[i].FirstNode;    while (p != null)    {        if (_vertexList[p.Index].Visited)            p = p.Next;        else            Dfs(p.Index, ref dfsResult);    }}

/// /// 得到深度优先搜索序列/// /// 进行深度优先搜索的起始点名称/// 深度优先搜索序列public string DfsTraversal(string startVertexName){    string dfsResult = string.Empty;    int i = GetIndex(startVertexName);    if (i != -1)    {        for (int j = 0; j             _vertexList[j].Visited = false;        Dfs(i, ref dfsResult);    }    return dfsResult;}

3.2 广度优先搜索

算法:

假设以为起点(源点)进行搜索。

首先标识为已访问结点,接着访问的邻接点然后访问的未被访问的邻接点,以此类推,直到与有路径相连的所有结点都被访问到。

先来先服务的思想。

例子:

图23 图的结构

深度优先搜索的序列为:

虽然遍历序列不唯一,但是邻接表确定后,遍历序列就唯一了。

实现:

图24 AdGraph结构
/// /// 得到广度优先搜索序列/// /// 进行广度优先搜索的起始点名称/// 广度优先搜索序列public string BfsTraversal(string startNodeName){    string bfsResult = string.Empty;    int i = GetIndex(startNodeName);    if (i != -1)    {        for (int j = 0; j             _vertexList[j].Visited = false;

        _vertexList[i].Visited = true;        bfsResult += _vertexList[i].VertexName + "\n";        LinkQueue<int> lq = new LinkQueue<int>();        lq.EnQueue(i);        while (lq.IsEmpty() == false)        {            int j = lq.QueueFront;            lq.DeQueue();            EdgeNode p = _vertexList[j].FirstNode;            while (p != null)            {                if (_vertexList[p.Index].Visited == false)                {                    _vertexList[p.Index].Visited = true;                    bfsResult += _vertexList[p.Index].VertexName + "\n";                    lq.EnQueue(p.Index);                }                p = p.Next;            }        }    }    return bfsResult;}

4. 拓扑排序

4.1 基本概念

网(Activity on Vertex Network):用顶点表示活动,用有向边表示活动之间先后关系的有向图。

拓扑序列:把网中的所有顶点排成一个线性序列,使每个活动的所有前驱活动都排在该活动的前边。

拓扑排序:构造网拓扑序列的过程。

例题:按照拓扑排序安排下列课程

图25 课程表

图26 AOV网

图27 AOV网的存储

4.2 算法步骤

第1步:从网中选择一个入度为0的顶点加入排序序列。

第2步:从网中删除该顶点及其所有出边。

第3步:执行第1、2步,直到所有顶点已排序或网中剩余顶点入度均不为0(说明:网中存在回路,无法继续拓扑排序)。

拓扑序列:

(1)

(2)

注:对于任何无回路的网,其顶点均可排成拓扑序列,但其拓扑序列未必唯一。

图28 存在回路的AOV网

存在回路的有向图,不能构成拓扑序列。

4.3 算法实现

图29 AdGraph结构
/// /// 得到每个节点的入度/// /// private int[] GetInDegressList(){    int[] id = new int[VertexCount];    for (int i = 0; i     {        EdgeNode p = _vertexList[i].FirstNode;        while (p != null)        {            id[p.Index]++;            p = p.Next;        }    }    return id;}

/// /// 得到AOV网的拓扑排序序列/// /// AOV网的拓扑排序序列public string TopoSort(){    string result = string.Empty;    int[] id = GetInDegressList();    LinkQueue<int> lq = new LinkQueue<int>();    for (int i = 0; i     {        if (id[i] == 0)            lq.EnQueue(i);    }

    if (lq.Length == VertexCount)        throw new Exception("此有向图无有向边.");

    while (lq.IsEmpty() == false)    {        int j = lq.QueueFront;        lq.DeQueue();        result += _vertexList[j].VertexName + "\n";

        EdgeNode p = _vertexList[j].FirstNode;        while (p != null)        {            id[p.Index]--;            if (id[p.Index] == 0)            {                lq.EnQueue(p.Index);            }            p = p.Next;        }    }    int k;    for (k = 0; k     {        if (id[k] != 0)        {            break;        }    }    return (k == VertexCount) ? result : "该AOV网有环.";}

5. 最小生成树

5.1 基本概念

生成树:设为连通网,具有的所有顶点(个)且只有条边的连通子网。

树的权:生成树的各边的权值总和。

最小生成树:权值最小的生成树。

5.2 Prim算法

算法原理(贪心算法):

设为连通网,为其对应的最小生成树,从开始构造。

(1)开始时,,。

(2)找到满足的边,把它并入中,同时并入。

(3)反复执行(2),直到时,终止算法。

例题:

图30 连通图

图31 连通图的存储

图32 最小生成树的构建

算法实现:

最小生成树结点的存储:

图33 最小生成树结点的结构

图34 SpanTreeNode结构
using System;

namespace NonLinearStruct{    ///     /// 生成树结点的抽象数据类型    ///     public class SpanTreeNode    {        ///         /// 获取或设置结点本身的名称        ///         public string SelfName { get; }

        ///         /// 获取或设置结点双亲的名称        ///         public string ParentName { get; }

        ///         /// 获取或设置边的权值        ///         public double Weight { get; set; }

        ///         /// 构造SpanTreeNode实例        ///         /// 结点本身的名称        /// 结点双亲的名称        /// 边的权值        public SpanTreeNode(string selfName, string parentName, double weight){            if (string.IsNullOrEmpty(selfName) || string.IsNullOrEmpty(parentName))                throw new ArgumentNullException();

            SelfName = selfName;            ParentName = parentName;            Weight = weight;        }    }}

图35 AdGraph结构
/// /// 得到连通网的最小生成树Prim算法/// /// 树根结点/// 连通网的最小生成树public SpanTreeNode[] MiniSpanTree(string vName){    int i = GetIndex(vName);    if (i == -1)        return null;

    SpanTreeNode[] spanTree = new SpanTreeNode[VertexCount];    spanTree[0] = new SpanTreeNode(_vertexList[i].VertexName, "NULL", 0.0);

    //U中结点到各结点最小权值那个结点在VertexList中的索引号    int[] vertexIndex = new int[VertexCount];    //U中结点到各个结点的最小权值    double[] lowCost = new double[VertexCount];    for (int j = 0; j     {        lowCost[j] = double.MaxValue;        vertexIndex[j] = i;    }

    EdgeNode p1 = _vertexList[i].FirstNode;    while (p1 != null)    {        lowCost[p1.Index] = p1.Weight;        p1 = p1.Next;    }    vertexIndex[i] = -1;

    for (int count = 1; count     {        double min = double.MaxValue;        int v = i;        for (int k = 0; k         {            if (vertexIndex[k] != -1 && lowCost[k]             {                min = lowCost[k];                v = k;            }        }        spanTree[count] = new SpanTreeNode(_vertexList[v].VertexName, _vertexList[vertexIndex[v]].VertexName, min);        vertexIndex[v] = -1;

        EdgeNode p2 = _vertexList[v].FirstNode;        while (p2 != null)        {            if (vertexIndex[p2.Index] != -1 && p2.Weight             {                lowCost[p2.Index] = p2.Weight;                vertexIndex[p2.Index] = v;            }            p2 = p2.Next;        }    }    return spanTree;}

5.3 Kruskar算法

设为连通网,为其对应的最小生成树。

(1)初始时,即中没有边,只有个顶点,就是个连通分量。

(2)在中选择权值最小的边,并将此边从中删除。

(3)如果,在的不同的连通分量中,则将加入到中,从而导致中减少一个连通分量。

(4)反复执行(2)(3)直到中仅剩一个连通分量时,终止操作。

例题:

图36 最小生成树的构建

图37 连通图的存储

图38 边的集合

算法实现:

图39 Edge结构
namespace NonLinearStruct.Graph{    ///     /// 表示图的边    ///     public class Edge    {        ///         /// 起点编号        ///         public int Begin { get; }

        ///         /// 终点编号        ///         public int End { get; }

        ///         /// 权值        ///         public double Weight { get; }

        ///         /// 创建一个 Edge 类的新实例        ///         /// 起点编号        /// 终点编号        /// 权值        public Edge(int begin, int end, double weight = 0.0){            Begin = begin;            End = end;            Weight = weight;        }    }}

图40 AdGraph结构
private Edge[] GetEdges(){    for (int i = 0; i         _vertexList[i].Visited = false;

    List result = new List();for (int i = 0; i     {        _vertexList[i].Visited = true;        EdgeNode p = _vertexList[i].FirstNode;while (p != null)        {if (_vertexList[p.Index].Visited == false)            {                Edge edge = new Edge(i, p.Index, p.Weight);                result.Add(edge);            }            p = p.Next;        }    }return result.OrderBy(a => a.Weight).ToArray();}private int Find(int[] parent, int f){while (parent[f] > -1)        f = parent[f];return f;}/// /// 克鲁斯卡尔算法 最小生成树/// /// public SpanTreeNode[] MiniSpanTree(){int[] parent = new int[VertexCount];for (int i = 0; i     {        parent[i] = -1;    }    SpanTreeNode[] tree = new SpanTreeNode[VertexCount];    Edge[] edges = GetEdges();int count = 1;for (int i = 0; i     {int begin = edges[i].Begin;int end = edges[i].End;int b = Find(parent, begin);int e = Find(parent, end);if (b != e)        {            parent[e] = b;            tree[count] = new SpanTreeNode(_vertexList[end].VertexName,                _vertexList[begin].VertexName, edges[i].Weight);            count++;        }    }for (int i = 0; i     {if (parent[i] == -1)        {            tree[0] = new SpanTreeNode(_vertexList[i].VertexName, "NULL", 0.0);break;        }    }return tree;}

6. 单源最短路径

6.1 定义

设为连通网,为源点,到其余各顶点的最短路径问题即为单源最短路径问题。

6.2 迪杰特撕拉算法

(迪杰特斯拉)算法(按路径长度递增顺序构造的算法):

初始时为源点,, ,标识被访问。

(1)令,(到的路径长度)。

(2)依次考察的未被访问的邻接点,若,则改变的值,使。

(3)在未被访问顶点中选择最小的顶点,访问。

(4)重复(2)、(3)直至所有顶点都被访问。

例题:

图41 原始图

图42 图的存储结构

图43 最短路径结果

算法实现:

图44 AdGraph结构
/// /// 单源最短路径/// /// 寻找最短路径的源点/// 源点到各个顶点的最短路径public string ShortestPath(string vName){    int v = GetIndex(vName);    if (v == -1)    {        return string.Empty;    }

    string result = string.Empty;    double[] dist = new double[VertexCount];    string[] path = new string[VertexCount];    //初始化    for (int i = 0; i     {        _vertexList[i].Visited = false;        dist[i] = double.MaxValue;        path[i] = _vertexList[v].VertexName;    }    dist[v] = 0.0;    _vertexList[v].Visited = true;

    for (int i = 0; i 1; i++)    {        EdgeNode p = _vertexList[v].FirstNode;        while (p != null)        {            if (_vertexList[p.Index].Visited == false                && dist[v] + p.Weight             {                dist[p.Index] = dist[v] + p.Weight;                path[p.Index] = path[v] + " ->" + _vertexList[p.Index].VertexName;            }            p = p.Next;        }

        double min = double.MaxValue;        for (int j = 0; j         {            if (_vertexList[j].Visited == false && dist[j]             {                min = dist[j];                v = j;            }        }        _vertexList[v].Visited = true;    }

    for (int i = 0; i     {        result += path[i] + ":" + dist[i] + "\n";    }

    return result;}

7. 连通分量

例题:

图45 原始图

图46 图的存储结构

可利用深度优先搜索,求非连通图的连通分量。

第一个:A,B,D,C;第二个:E,F;第三个:G,H,I

算法实现:

图47 AdGraph结构
/// /// 得到连通分量/// /// 连通分量public string ConnectedComponent(){    string result;    SLinkList<string> lst = new SLinkList<string>();

    for (int i = 0; i         _vertexList[i].Visited = false;

    for (int i = 0; i     {        if (_vertexList[i].Visited == false)        {            result = string.Empty;            //利用深度优先搜索求非连通图的连通分量            Dfs(i, ref result);            lst.InsertAtRear(result);        }    }    result = string.Empty;    for (int i = 0; i     {        result += "第" + i + "个连通分量为:\n" + lst[i];    }    return result;}

8. 练习

根据要求完成程序代码:

给定纽约市附近的一幅简单地图,图中的顶点为城市,无向边代表两个城市的连通关系,边上的权为两城市之间的距离。

图48 纽约市附近地图

(1)对该图进行深度优先和广度优先搜索,并输出搜索序列(图的搜索问题)。

(2)在分析这张图后可以发现,任一对城市都是连通的。

第一个问题是:要用公路把所有城市连接起来,如何设计可使得工程的总造价最少(最小生成树问题)。

第二个问题是:要开车从一个城市到另外一个城市求其最短距离以及驱车路线(最短路径问题)。

解答:

数据TXT文件:

Source,Target,WeightSan Rapheal,Cross,12San Rapheal,Oakland,18Cross,Daly Cit,3Cross,San Franciso,3Daly Cit,San Franciso,4Daly Cit,Cross B,19San Franciso,Oakland,7San Franciso,San Mateo,21Oakland,San Iarenzo,18Oakland,Dublin,31San Iarenzo,Hayward,3San Iarenzo,Dublin,12Cross B,San Mateo,4Cross B,Cross C,7San Mateo,Hayward,13San Mateo,Redwood City,6Hayward,Freemont,9Dublin,San Jose,35Redwood City,Cross C,5Redwood City,Palo Alto,6Cross C,Cupertin,14Palo Alto,Freemont,9Palo Alto,Mtn View,6Freemont,San Jose,24Mtn View,Cupertin,6Mtn View,San Jose,8Cupertin,San Jose,7

深度优先搜索序列:

San RaphealCrossDaly CitSan FrancisoOaklandSan IarenzoHaywardSan MateoCross BCross CRedwood CityPalo AltoFreemontSan JoseDublinMtn ViewCupertin

广度优先搜索序列:

San RaphealCrossOaklandDaly CitSan FrancisoSan IarenzoDublinCross BSan MateoHaywardSan JoseCross CRedwood CityFreemontMtn ViewCupertinPalo Alto

最小生成树:

(NULL,San Rapheal) Weight:0(San Rapheal,Cross) Weight:12(Cross,Daly Cit) Weight:3(Cross,San Franciso) Weight:3(San Franciso,Oakland) Weight:7(Oakland,San Iarenzo) Weight:18(San Iarenzo,Hayward) Weight:3(Hayward,Freemont) Weight:9(Freemont,Palo Alto) Weight:9(Palo Alto,Redwood City) Weight:6(Redwood City,Cross C) Weight:5(Redwood City,San Mateo) Weight:6(San Mateo,Cross B) Weight:4(Palo Alto,Mtn View) Weight:6(Mtn View,Cupertin) Weight:6(Cupertin,San Jose) Weight:7(San Iarenzo,Dublin) Weight:12

最小生成树权值:116

最短路径:

San Rapheal:0San Rapheal ->Cross:12San Rapheal ->Oakland:18San Rapheal ->Cross ->Daly Cit:15San Rapheal ->Cross ->San Franciso:15San Rapheal ->Cross ->Daly Cit ->Cross B:34San Rapheal ->Cross ->San Franciso ->San Mateo:36San Rapheal ->Oakland ->San Iarenzo:36San Rapheal ->Oakland ->San Iarenzo ->Dublin:48San Rapheal ->Oakland ->San Iarenzo ->Hayward:39San Rapheal ->Cross ->Daly Cit ->Cross B ->Cross C:41San Rapheal ->Cross ->San Franciso ->San Mateo ->Redwood City:42San Rapheal ->Oakland ->San Iarenzo ->Hayward ->Freemont:48San Rapheal ->Cross ->San Franciso ->San Mateo ->Redwood City ->Palo Alto ->Mtn View ->San Jose:62San Rapheal ->Cross ->San Franciso ->San Mateo ->Redwood City ->Palo Alto:48San Rapheal ->Cross ->Daly Cit ->Cross B ->Cross C ->Cupertin:55San Rapheal ->Cross ->San Franciso ->San Mateo ->Redwood City ->Palo Alto ->Mtn View:54

python中判断无向图是否有环_数据结构与算法:17 图相关推荐

  1. java 单链表是否有环_数据结构与算法随笔之链表-链表是否有环(二)

    上一篇文章我们分析了下链表之反转单向链表,这篇文章我们来分析下另外一个关于链表的经典题目. 判断链表是否有环(在leetcode上的题目地址:环形链表) 题目描述 给定一个链表,判断链表中是否有环 解 ...

  2. 栈判断字符串是否为中心对称_数据结构和算法入门之判断括号字符串的合法性(valid parentheses)...

    今天终于开始看栈的部分咯!栈这个东西没啥好介绍的,我想基本只要写过一丢丢代码的人已经都非常清楚了.今天这个题目是一个非常简单但是也很经典地用到栈这个数据结构的题,废话不多说,原题链接如下: Loadi ...

  3. arrays中copyof复制两个数组_数据结构与算法(3)数组

    前言 数组(Array)是一种线性表数据结构,利用一组连续的内存空间,存储一组具有相同类型的数据. 概念介绍 首先我们说一下什么是线性表,线性表就是数据排成一条线的数据结构,每个线性表最多只有前和后两 ...

  4. Python 判断无向图是否存在环

    代码实现 def has_cycle(G):"""判断无向图是否有环:param G: example {0: [1,2],1: [3], 2: []}:return:T ...

  5. Python中判断两个字符串的内容是否相同

    1 前言 今天在划分数据集的时候,需要判断两个字符串的内容是否相同,这个之前查过,不过好像忘记了,所以想着再记录一下- 2 Python中判断两个字符串的内容是否相同 使用"==" ...

  6. python判断字符串合法,详解Python判定IP地址合法性的三种方法 python中判断一个字符串是否是IP地址...

    html 中 鼠标放在标签上会显示小手状,其它标签在其他标签上,美工给加了一些样式,鼠标放上去也显示小手状.有哪位大手状样式 有什么不懂的前端问题可以去菜鸟驿站.全都是泡沫,只一刹的花火,所谓的友情, ...

  7. python中判断字符串中出现次数最多的字母

    python中判断字符串中出现次数最多的字母 import string def check(text):text = text.lower()return max(string.ascii_lowe ...

  8. 创建二维数组 以及 python中[0 ]* n与[0 for _ in range(n)]的区别与联系

    一.浅拷贝于深拷贝 关于浅拷贝于深拷贝:Python 的深拷贝和浅拷贝 直接赋值:其实就是对象的引用(别名). 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象. 深拷贝(deepcopy) ...

  9. (不带头结点的)单链表增删查改,逆置单链表(两种方法),求两个单链表的第一个公共结点,合并两个单链表,单循环链表中判断第一个入环点,约瑟夫环

    补充了每个算法的基本思想,并且画了思路图,源代码都经过调试成功 1.SlistNode.c文件 (1) (不带头结点的)单链表增删查改 #include "SlistNode.h" ...

最新文章

  1. 【iOS】Mapkit的使用:地图显示、定位、大头针、气泡等
  2. 如何用html制作心,html – 如何创建CSS心脏? /为什么这个CSS创造一个心脏的形状?...
  3. 把Vi改造成Vim的作者,现在又让Vim快了70倍
  4. 【洛谷 2709】小B的询问
  5. 随时随地以任意方式编写 .NET 应用程序
  6. 数据结构与算法--位运算
  7. ApacheCN Angular 译文集 20211114 更新
  8. 华为鸿蒙微内核已经投入商用;PC 端将支持打开小程序;VS Code 1.37 发布 | 极客头条...
  9. wxpython frame鼠标拖动_Python wxpython模块响应鼠标拖动事件操作示例
  10. 运动目标跟踪(一)--搜索算法预测模型之KF,EKF,UKF
  11. EP Limited: 开源ECG分析软件介绍
  12. 不要随便参加业主群的赏月大赛
  13. 精伦身份证阅读器php_精伦IDR210台式身份证读卡器
  14. android系统输入法下载官网下载地址,kazakhsha kirgizwshi下载
  15. P10(1R)单红V706模组32X16 LED显示屏的二十项小实验
  16. [机缘参悟-74]:沟通技巧-无论在职场还是在家,尽量少用反问句
  17. 《慢慢来,一切都来得及》语录
  18. javaweb接口开发
  19. 【Transformer专题】一、Attention is All You Need(Transformer入门)
  20. 深度学习框架Caffe学习系列(2):Ristretto 量化 cifar_small 实验记录

热门文章

  1. 定量分析双花(双重支付)问题
  2. flutter项目引入iconfont【阿里巴巴图标】的图标
  3. c++11的regex使用
  4. CentOS 7.6 部署frps
  5. 一个初中生到程序员的辛酸经历(转载)
  6. TYVJ 木瓜地
  7. Thinkphp3.2 表达式查询eq,neq,gt,egt,lt,elt,in,between,like,exp
  8. mysql二级考试范围_计算机二级MySQL考试内容大纲
  9. Wangle源码分析:Service
  10. python中shelf对象_shelve -- 用来持久化任意的Python对象