王道数据结构6(图)

Posted 晨沉宸辰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了王道数据结构6(图)相关的知识,希望对你有一定的参考价值。

一.概念

顶点
V(顶点的有穷非空集合)
VR(两个顶点之间的关系集合)
:(有向图,无向图)
n图中顶点的数目
e表示边和弧的数目
无向完全图(有n(n-1)/2条边的无向图)
有向完全图(有n(n-1)条弧有向图)
稀疏图,稠密图

:带网的图
子图
邻接点:顶点之间邻接
顶点的度
入度(ID)和出度(OD)
路径长度
回路
简单路径:序列中顶点不重复的路径
环回路:除第一个顶点和最后一个顶点之外,其余顶点不重复出现
连通图
连通分量:无向图的极大连通子图
强连通图
强连通分量:有向图的极大强连通子图称为有向图的强连通分量。
一个连通图的生成树:是一个极小连通子图,它含有图中全部顶点,但只有足以构成一棵树的n-1条边。

二.图的储存结构(邻接矩阵法)

1.数组表示法

【1】有向图
G1的邻接矩阵为:


【2】无向图
G2的邻接矩阵为:


网的邻接矩阵定义为:

a[i][j]:
(1) Wij 若<vi,vj> 或(vi,vj )∈VR

(2)∞ 反之

说明:1.对于无向图,顶点vi的度是邻接矩阵中第i行(或第i列)的元素之和,
TD(vi)= ∑ a[i][j]
2.对于有向图,顶点VI的出度OD(vi)是邻接矩阵中第i行的元素之和,顶点vi的出度ID(vi)是邻接矩阵中第j列)的元素之和,

2. 定义邻接矩阵的结构

#define INFINITY INT_MAX
#define MAX_VERTEXT_NUM 20
typedef enumDG,DN,AG,ANGraphKind;
typedef struct ArcCell
  VRType adj;//对无向图,用0,1表示是否相邻,对于带权图,为权值
  InfoType *info;//该弧相关信息的指针

RrcCell,AdjMatrix[MAX_VERTEXT_NUM][MAX_VERTEXT_NUM];//邻接矩阵

3. 定义图的结构

//定义图的结构
typedef struct 
   VertextType exs[MAX_VERTEXT_NUM];
   AdjMatrix arcs[MAX_VERTEXT_NUM][MAX_VERTEXT_NUM];
   int vexnum,arcnum;
   GraphKind kind;
MGraph;

4. 构造图G

status CreateGraph(MGraph &G)

    scanf(&G.kind)
    
        case DG:return CreateDG(G);
         case DN:return CreateDN(G);
           case UDG:return CreateUDG(G);
             case UDN:return CreateDGN(G);
        default:return ERROR;
    

//用无向图为例

status CreateUDN(MGraph &G)

    scanf(&G.arcnum,&G.vexnum,&IncInfo);//输入点数和边数
    //给顶点进行数字化编号
    for(i=0;i<G.vexnum;i++)
     scanf(&G.exs[i]);//定义顶点数组(如果顶点本身就是1~n的数字无需这一步)
    
    //初始化邻接矩阵
    for(i=0;i<G.vexnum;i++)
    
        for(j=0;j<G.vexnum;j++)
        
            G.arcs[i][j]=ININITY,NULL;
        
    
    //通过边数进行遍历
    for(k=0;k<G.arcnum;K++)
    
        scanf(&V1,&V2,&W);//输入邻接的连个顶点
        i=locatteVex(G,V1);j=locateVex(G,V2);//查找V1,V2的位置
        G.arcs[i][j].adj=w;//给邻接矩阵赋值
        if(IncInfo)
        
            INPUT(*G.arcs[i][j].info);
        
        G.arcs[j][i]=G.arcs[i][j];//由于是无向图,对称
    
    return ok;


5. 特点

优点

  • 无向图邻接矩阵是对称矩阵,同一条边表示了两次

  • 顶点v的度:等于二维数组对应行(或列)中1的个数

  • 判断两顶点v、u是否为邻接点:只需判二维数组对应分量是否为1

  • 在图中增加、删除边:只需对二维数组对应分量赋值1或清0

  • 占用存储空间只与它的顶点数有关,与边数无关;适用于边稠密的图

  • 对有向图的数组表示法可做类似的讨论
    缺点

  • 不便于删除和增加顶点

  • 不便于统计边的数目,需要扫描邻接矩阵所有元素才能统计完毕,时间复杂度为O(n2 )

  • 空间复杂度高,对于有向图,n个顶点需要n2 个单元存储边,对于无向图,n(n-1)/2个单元,空间复杂度为O(n2 )

三. 储存结构(邻接表表示法)

1. 储存方式

【1】无向图

  • 把从一个顶点出发的边链接在一个单链表(又名边链表)中把从一个顶点出发的边链接在一个单链表(又名边链表)中
  • 所有边链表的表头指针放在一个顺序表中

【2】有向图



注意,在有向图的邻接表中不易找到指向该顶点的弧。

2. 结构

【1】顶点的结点结构

———————
| data | firstarc |
———————

  • data数据域:储存顶点vi
  • firstarc链域:指向链表中第一个结点

【2】弧的结点结构

——————————
| adjvex | info | nextarc |
——————————

  • adjvex邻接点域:与顶点vi邻接的点在图中的位置
  • info数据域:储存和边相关的信息,如权值
  • nextarc链域:与顶点vi的点在图中的位置

3.图的邻接表存储表示(算法)

#define MAX_VERTEXT_NUM 20
//建立边结点 
typedef struct ArcNode 
      int adjvex;                      // 该弧所指向的顶点的位置
      struct ArcNode *nextarc; // 指向下一条弧
      InfoType  *info;                // 该弧相关信息(可选)
ArcNode; 
// 顶点结点
typedef struct VNode
        VertexType data;              // 顶点信息
        ArcNode  *firstarc;          // 指向第一条依附该顶点的弧
VNode,AdjList[MAX_VERTEXT_NUM];
//邻接表
typedef struct 
      Adjlist vertices;
      int vexnum,arcnum;
      int kind;
ALGraph; 
//建立邻接表算法
//初始化一个结点总数为num的图,k为图的类型,num为结点总数
void InitG(ALGraph G,enum GraphKind k,int num)

    G.kind=k;
    G.vexnum=num;
    G.vertices=new VNode[vexnum];
    for(int i=0;i<G.vexnum;i++)
    G.vertices[i].Firstarc=NULL;
        cin>>G.vertics[i].data;
    


//有向图(网)增加弧的算法,将弧(from,to,weight)加入图
void InsertArc(ALGragh G,int from,int to,int weight)

    ArcNode *s=new ArcNode;
    s->weight=weight;
    s->adjvex=to;
    s->nextarc=G.vertices[from].firstarc;//插到链表vertices[from]的头
    G.vertices[from].firstarc=s;


  • 在邻接表中,同一条边对应两个结点;
  • 顶点v的度:等于v 对应的链表的长度;
  • 判定两顶点v,w是否邻接:要看v对应的链表中有无对应的结点w(相反判断也行);
  • 增减边:要在两个单链表插入、删除结点;
  • 占用存储空间与顶点数、边数均有关;适用于边稀疏的图

四.图的遍历

1. 图遍历的概述

1、定义——从某顶点出发,沿着一些边访问连通图中所有顶点,且使每个顶点仅访问一次的运算。
2、为避免重复访问,可设置辅助数组Visited[ ],各分量初值为0,当顶点被访问,对应分量被置为1。
3、方法——深度优先(depth first search DFS)
广度优先(breadth first search BFS)

2.深度优先遍历

###(1)算法描述
从图中某个顶点V0 出发,访问此顶点,然后依次从V0的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和V0有路径相通的顶点都被访问到。
~
W1、W2和W3 均为 V 的邻接点,SG1、SG2 和 SG3 分别为含顶点W1、W2和W3 的子图。
从上页的图解可见::

  1. 从深度优先搜索遍历连通图的过程类似于树的先根遍历;
  2. 如何判别V的邻接点是否被访问?
    解决的办法是:为每个顶点设立一个 “访问标志数组bool visited[vexnum]”。
    ###(2)算法实现
  1. 邻接矩阵
int visited[MAX];//设置一个数组,判断是否遍历过,false/1为遍历过
void DFGTraverse(Graph G,int v)

    for(v=0;v<G.vexnum;v++)
       visited[v]=0;//初始化判断数组
    for(v=0;v<G.vexnum;v++)
    
        if(!visited[v])//如果没有遍历过
            DFS(G,V);//进行遍历
    

void DFS(Graph G,int v)//进行递归遍历

    visited[v]=1;printf(v);//改变判断数组,输出点
    for(w=FirstVex(G,v);w!=0;w=NextVex(G,v))//从每一行第一个邻接矩阵值为1的,跳转到下一个值为1的
    
        if(!visited[w])
            DFS(G,v);
    

int FirstVex(Graph G,int v)//判断第一个不是0的

    int i;
    for(i=0;i<G.vexnum;i++)
    
        if(G.arcs[v][i]==1&&visited[i]==False)
            return i;
    
    return -1;

void NextVex(Graph G,int v)//判断下一个不是0的

    int i;
    for(i=w;i<G.vexnum;i++)
    
        if(G.arcs[v][i]==1&&visited[i]!=False)
            return i;
    
    return -1;

2.邻接表

void DFS(Graph G,int v)

    cout<<G.vertices[v].data<<"  ";
    visited[v]=true;
    ArcNode *p=G.vertices[v].firstarc;
    while(p!=NULL)
    
        int w=p->adjvex;
        if(!visited[w])
            DFS(G,w);
        p=p->nextarc;a
    

(3)时间复杂度

T(n)=o(n2) 邻接矩阵
T(n)=O(e+n) 邻接表

3. 广度优先遍历

(1)算法描述

  • 从图中某个顶点V0出发,并在访问此顶点之后依次访问V0的所有未被访问过的邻接点,之后按这些顶点被访问的先后次序依次访问它们的邻接点,直至图中所有和V0有路径相通的顶点都被访问到。
  • 对于非连通图,可能此时尚有顶点未被访问,则另选图中一个未被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。

(2)例子:


(3)算法

以上是关于王道数据结构6(图)的主要内容,如果未能解决你的问题,请参考以下文章

计算机组成原理 王道考研2021 第二章:数据的表示和运算 -- 浮点数的表示和IEEE754标准

计算机组成原理 王道考研2021 第二章:数据的表示和运算 -- 定点数vs浮点数定点数的表示(原/反/补/移码)原/反/补/移码作用

王道数据结构与算法串

王道计算机网络绪论与体系结构(零)

计算机组成原理 王道考研2021 第二章:数据的表示和运算 -- 本章小结常见问题和易混淆知识点

王道计算机组成原理笔记11 浮点数的表示