数据结构与算法之图(上)

什么是图

图是一种非常强大的数据结构,图是由顶点的有穷非空集合和顶点之间边的集合组成,通

常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。

当我们需要处理多对多这么一种关系时,我们就可以建立一张图来解决。图中的顶点是我

们的数据元素(线性表中我们把数据元素叫元素,树中叫结点,在图中数据元素我们则称

之为顶点),边就是这些研究对象之间的关系,通常称之为权重,具体应用中会有不同。

怎么存储图

邻接矩阵

在这里插入图片描述
用一个二维数组存放节点,节点之间有边的就把对应的数组元素赋值位1,代表存在。

邻接矩阵的好处就是能够直观的看到那些边之间存在关系,便于查询(只要输入你要查询

的两个顶点值便可以确定他在这个二维数组当中的位置),计算每一个顶点的入度或出度

时只需遍历一遍即可。

代码实现邻接矩阵构建图:
在这里插入图片描述
但我们不难发现这个二维数组沿红线分开的两部分是完全对称的,且红线上的值都为0(自

己到自己肯定是没有边的啦),精打细算的我们就会想能不能那一半不用可以节省点空间

啊!
在这里插入图片描述
于是我们有了上面这个解决方案,他优化了邻接矩阵的空间复杂度,但他也制造了一些不

便,变成一个一维数组来存储之后,查询是否存在边变得没那么容易,如果我们要查询点

Vi与Vj之间有没有边就要查询a[i*(i+1)/2+j]了。但无论怎样还是节省了空间。

我们知道建立一个邻接矩阵就是为了存储一个图当中的关联关系,就是我们的边,矩阵中

为1的就代表着有边,但如果便很少一个矩阵里面大部分都是0,如果边多还好说,用了不

亏嘛,但这个点多边还少那肯定会导致大量的空间浪费(几万个点我就存两条边),所以

聪明的我们又想到了链表。

邻接表

在这里插入图片描述
对于所有的顶点我们都建立一个指针构成一个指针数组,将与其有关的顶点连接至他的

next指针,这样就形成了邻接表,邻接表只存有关系的,当我们面对一个稀疏图时,邻接

表便显得那么的简洁。对于带权值的网图,可以在边表结点定义中再增加一个数据域来存

储权值即可。邻接表还能很方便的找到任一顶点的邻接点。

但邻接表也是有缺点的,在零阶矩阵当中我们表示边的存在时用的是1来表示他只占了一个

字节,但在邻接表里如果两点之间存在边,他既会出现在Vi的单链表里还会出现在VJ

里,而且我们不仅要存一个数据域,还要有一个指针域,如果带有权重还得要有一个数据

域,那样就占用了三个字节了。在用邻接表存储图后,计算出度入度对于无向图是和邻接

矩阵无异的,遍历一边即可,但对于无向图而言,还需要再建立一个逆邻接表才能实现,

所以,要用邻接表的话,一定要稀疏才合算啊。

图的遍历

我们存储完一个图之后,我们肯定要取用他,图怎么用,那就是遍历,图的遍历分为DFS和BFS。

在这里插入图片描述
深度优先顾名思义就是优先往深的地方走(一条路走到黑),直到走不下去或者达到终点

他才会终止,其实这里面也是用到了一个递归,当碰到不能走之后,它会返回他的上一层

往另一个方向继续搜索。

代码实现:

void dfs(int x, int y, int step) 
{
    if(mp[x][y]=='D'&&step==T)
    {
     flag=1;
     return;
 }
    vis[x][y]=1;
    for(int i=0;i<4;++i)
 {
        int x1=x+dir[i][0];
        int y1=y+dir[i][1];
        if(in(x1,y1)&&mp[x1][y1]!='X'&&!vis[x1][y1])
  {
   vis[x1][y1]=1;
   dfs(x1,y1,step+1);
            if(flag)
                return ;
            vis[x1][y1]=0;
        }
    }
}

在这里插入图片描述
广度优先搜索是一圈一圈往外搜的,所以我们在这个地方用队列来实现,从起点出发将与

其相关的顶点入队,将自己出队,不断重复操直至所有顶点出队,或找到符合条件终止。
代码实现:

void bfs(struct node start)
{
    Q.push(start);
    book[start.x][start.y]=1;
    while(!Q.empty())
    {
        struct node now=Q.front();
        Q.pop();
        if(now.step>0&&(now.x==1||now.x==n||now.y==1||now.y==m))
        {
            ans=now.step;
            return;
        }
        for(int i=0; i<4;i++)
        {
         struct node neww;
            neww.x=now.x+dir[i][0];
            neww.y=now.y+dir[i][1];
            neww.step=0;
            if(neww.x>0&&neww.x<=n&&neww.y>0&&neww.y<=m&&!book[neww.x][neww.y]&&mp[neww.x][neww.y]=='.')
            {
                book[neww.x][neww.y]=1;
                if(now.step>0)
                     neww.step=now.step+1;
                Q.push(neww);
            }
        }
    }
}

dfs空间复杂度小于bfs,bfs的时间复杂度小于dfs

dfs与bfs可谓各有千秋吧(不过我们好像更加关注的是时间复杂度,bfs用的还是要多一点啊)

发布了32 篇原创文章 · 获赞 5 · 访问量 897

猜你喜欢

转载自blog.csdn.net/LebronGod/article/details/104442010