数据结构——图 基本概念及存储结构

基本概念

在图形结构中,结点之间的关系可以是任意的,图中任意两个数据元素之间都可能相关。

在图中的数据元素通常称为顶点,V是顶点的有穷非空集合,VR是两个顶点之间的关系的集合。

有向图与无向图

若两个顶点之间的关系表示为<v, w>∈VR,称此时的图为有向图。

若<v, w>∈VR必有<w, v>∈VR,即VR是对称的,称此时的图为无向图。

如果用n表示顶点数目,e表示边或弧的数目,那么有 1/2*n*(n-1) 条边的无向图称为完全图

具有 n* (n-1) 条弧的有向图称为有向完全图

有时图的边或弧具有与它相关的数,这种与图的边或弧相关的数叫做,这些权可以表示从一个顶点到另一个顶点的距离或耗费。这种带权的图通常称为网。

顶点v的是和v相关联的边的数目。

对于有向图来说,以顶点v为头的弧的数目称为v的入度;以v为尾的弧的数目称为v的出度

图的路径

无向图中从顶点v到顶点v'的路径是一个v到v'可达的关联起来的顶点序列。

第一个顶点和最后一个顶点相同的路径称为回路或环。序列中顶点不重复出现的路径称为简单路径。除了第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路,称为简单回路或简单环

连通

在无向图中,如果从顶点v到顶点v'有路径,则称v和v'是连通的。

如果对于图中的任意两个顶点都∈V,他们都是连通的,则称这个图是一个连通图

连通分量,指的是无向图中的极大连通子图。

在有向图中,如果对于每一对顶点都∈V,他们相互之间都存在路径,则可称为强连通图

有向图中的极大连通子图称为有向图的强连通分量

一个连通图的生成树是一个极小连通子图,它包含有图中全部顶点,但只有足以构成一棵树的n-1条边。

如果一个有向图恰有一个顶点的入度为0,其余顶点的入度均为1,则是一颗有向树。

存储结构

数组表示法(邻接矩阵)

1 表示相连接,0 表示不相连。可以轻易知道两个顶点之间是否相连。

邻接表

只表达和顶点相连接的顶点信息,用邻接表表示图比邻接矩阵节省存储空间。在邻接表上容易找到任一顶点的第一个邻接点和下一个邻接点,但要判定任意两个顶点之间是否有边或弧相连,则需搜索该顶点所在的整个链表。

using System.Collections.Generic;
using UnityEngine.Assertions;

namespace Graph
{
    public class SparseGraph 
    {
        // 节点数
        private int n;
        // 边数
        private int m;
        // 是否为有向图
        private bool directed;
        // 图的具体数据
        private List<int>[] g;

        // 构造函数
        public SparseGraph( int n , bool directed )
        {
            Assert.IsTrue(n >= 0);
            this.n = n;
            this.m = 0;  
            this.directed = directed;
            // g初始化为n个空的vector, 表示每一个g[i]都为空, 即没有任和边
            g = new List<int>[n];
            for (int i = 0; i < n; i++)
                g[i] = new List<int>();
        }
        
        // 返回节点个数
        public int V(){ return n;}
        // 返回边的个数
        public int E(){ return m;}
        // 向图中添加一个边
        public void AddEdge(int v, int w)
        {
            Assert.IsTrue(v >= 0 && v < n);
            Assert.IsTrue(w >= 0 && w < n);
            g[v].Add(w);
            if (v != w && !directed)
                g[w].Add(v);
            m++;
        }

        // 验证图中是否有从v到w的边
        bool HasEdge(int v, int w)
        {
            Assert.IsTrue(v >= 0 && v < n);
            Assert.IsTrue(w >= 0 && w < n);

            for (int i = 0; i < g[v].Count; i++)
                if (g[v][i] == w)
                    return true;
            return false;
        }
    }
}

十字链表

可以看成是有向图的邻接表和逆邻接表结合起来得到的一种链表。

在十字链表中,容易找到以vi为头的弧,因而容易求得顶点的出度和入度(如需要,可在建立时同时求出)。 

邻接多重表

在邻接表中每一条边(vi,vj)有两个结点,分别在第i个链表和第j个链表中,给这些图的操作带来不便。例如在某些图的应用中需要对边进行某种操作,如对已被搜索过的边做记号或删除一条边等,需要找到表示同一条边的两个结点。因此,这一类无向图的问题中采用邻接多重表更为合适。

对无向图而言,邻接多重表和邻接表的差别,仅仅在于同一条边在邻接表中用两个结点表示,而在邻接多重表中只有一个结点。因此,它在边结点中增加一个标识域。

猜你喜欢

转载自blog.csdn.net/dmk17771552304/article/details/120389113