图的存储和图的遍历

图的存储

邻接矩阵

邻接矩阵存储不带权图

无向图:若AB之间有边,则表中AB的值为1

在这里插入图片描述

**有向图:**若有A->B的边,则A行B列的值为1

在这里插入图片描述

#define MaxVertexNum 100
typedef struct{
    char Vex[MaxVertexNum]; //顶点表
    int Edge[MaxVertexNum][MaxVertexNum]; //邻接矩阵、边表 也可换成bool类型数据
    int vexnum,arcnum;  //图中顶点和边的个数
}MGraph;
  • 无向图求顶点的度:若要求顶点A的度,则只需要遍历A行表中元素不为0的个数。第i个结点的度=第i行(第i列)的非零元素个数

  • 有向图求顶点的入度出度

    若要求A的出度,则要遍历A行表中元素不为0的个数(第i个结点的出度=第i行非零元素的个数)

    若要求入度,则要遍历A列表中元素不为0的个数(第i个结点的入度=第i列非零元素的个数)

    第i个结点的度=入度+出度。

邻接矩阵存储带权图

在这里插入图片描述

#define MaxVertexNum 100
#define INFINITY 最大的int//宏定义无穷
typedef char VertexType; //顶点的数据类型
typedef int EdgeType;    //带权图边上权值的类型
typedef struct{
    VertexType Vex[MaxVertexNum];
    EdgeType Edge[MaxVertexNum][MaxVertexNum];
    int vexnum,arcnum;
}MGraph;
邻接矩阵法的性能分析

时间复杂度:O(n)

空间复杂度:O(n2)=O(|V|2) --只和顶点的个数有关,与实际的边数无关

⭐⭐⭐适合用于存储稠密图,稀疏图会浪费大量空间

无向图的邻接矩阵是对称矩阵,可以压缩存储(只存储上三角区/下三角区)

⭐邻接矩阵性质

设图G的邻接矩阵为A(矩阵元素为0/1),则An的元素Anij等于由顶点i到顶点j的长度为n的路径的数目。

在这里插入图片描述

邻接表

在这里插入图片描述

如图所示,使用邻接表法存储需要使用数组+链表的方式

#define MaxVertexNum 100
typedef struct ArcNode{  //边结点
    int adjvex;   //该弧所指向的顶点的位置
    struct ArcNode *nextare; //指向下一条边的指针
    // InfoType info; //边上的权值  网的边权值
}ArcNode;
typedef struct VNode{  //顶点表结点
    VertexType data; //定点表的信息
    ArcNode *firstarc //指向第一条依附该顶点的弧的指针
}VNode,AdjList[MaxVertexNum];
typedef struct{    //邻接表
    AdjList vertices; //邻接表
    int vexnum,arcnum; //顶点和边的个数
}

邻接表 邻接矩阵 空间复杂度 无向图 O ( ∣ V ∣ + 2 ∣ E ∣ ) ; 有向图 O ( ∣ V ∣ + ∣ E ∣ ) O ( ∣ V ∣ 2 ) 适用于 存储稀疏图 存储稠密图 表示方式 不唯一 唯一 计算出度 / 入度 / 度 计算有向图的度、入度不方便,其余很方便 必须遍历对应的行和列 找相邻的边 找有向图的入边不方便,其余很方便 必须遍历对应的行和列 \begin{array}{|c|c|c|} \hline &邻接表 &邻接矩阵\\ \hline 空间复杂度 & 无向图O(|V|+2|E|);有向图O(|V|+|E|) & O(|V|^2)\\ \hline 适用于 & 存储稀疏图 & 存储稠密图\\ \hline 表示方式 & 不唯一 & 唯一\\ \hline 计算出度/入度/度 & 计算有向图的度、入度不方便,其余很方便 &必须遍历对应的行和列\\ \hline 找相邻的边 &找有向图的入边不方便,其余很方便 &必须遍历对应的行和列\\ \hline \end{array} 空间复杂度适用于表示方式计算出度/入度/找相邻的边邻接表无向图O(V+2∣E);有向图O(V+E)存储稀疏图不唯一计算有向图的度、入度不方便,其余很方便找有向图的入边不方便,其余很方便邻接矩阵O(V2)存储稠密图唯一必须遍历对应的行和列必须遍历对应的行和列

十字链表(存储有向图)

在这里插入图片描述

空间复杂度:O(|V|+|E|)

出边:顺着绿色的线路找

入边:顺着橙色的线路找

⭐Attention:只能存储有向图

#define MaxVertexNum 100
typedef struct ArcNode{  //边结点
    int headvex;   //弧头编号
    int tailvex;   //弧尾编号
    struct ArcNode *hlink; //弧头相同的下一条弧
    struct ArcNode *tlink; //弧尾相同的下一条弧
    // InfoType info; //边上的权值  网的边权值
}ArcNode;

typedef struct VNode{  //顶点表结点
    VertexType data; //顶点表的信息
    ArcNode *firstin; //该顶点作为弧头的第一条弧
    ArcNode *firstout; //该顶点作为弧尾的第一条弧
}VNode;

邻接多重表(存储无向图)

在这里插入图片描述

typedef struct ArcNode{ //边结点
    int i,j; //边结点所连接的两个顶点的编号
    struct ArcNode *ilink; //依附于顶点i的下条边
    struct ArcNode *jlink; //依附于顶点j的下条边
    //InfoType Info; // 权值
}ArcNode;

typedef struct VNode{
    VertexType data; //顶点的数据
    ArcNode *firstedge; //顶点所连接的第一条弧结点
}VNode, AdjList[MaxVertexNum];

typedef struct{    //邻接表
    AdjList vertices; //邻接表
    int vexnum,arcnum; //顶点和边的个数
}

空间复杂度:O(|V|+|E|)

⭐Attention:只能存储无向图
十字链表 邻接多重表 空间复杂度 O ( ∣ V ∣ + ∣ E ∣ ) O ( ∣ V ∣ + ∣ E ∣ ) 找相邻边 很方便 很方便 删除边或者顶点 很方便 很方便 适用于 只能存有向图 只能存无向图 表示方式 不唯一 唯一 \begin{array}{|c|c|c|} \hline & 十字链表&邻接多重表\\ \hline 空间复杂度 &O(|V|+|E|)&O(|V|+|E|)\\ \hline 找相邻边 &很方便 &很方便\\ \hline 删除边或者顶点 &很方便&很方便\\ \hline 适用于 &只能存有向图 &只能存无向图\\ \hline 表示方式 &不唯一 &唯一\\ \hline \end{array} 空间复杂度找相邻边删除边或者顶点适用于表示方式十字链表O(V+E)很方便很方便只能存有向图不唯一邻接多重表O(V+E)很方便很方便只能存无向图唯一


图的遍历

广度优先遍历(BFS)⭐

算法要点
  • 需要一个辅助队列
  • 从一个结点找到与之邻接的其他结点
  • visited数组防止重复访问
  • 如何处理非连通图
算法实现

在这里插入图片描述

bool visited[MAX_VERTEX_NUM];
void BFSTraverse(Graph G){  //对图进行广度优先遍历
    for(int i=0;i<G.vexnum;++i)
        visiited[i]=false;  //初始化visited表
    InitQuene(Q);  //初始化队列
    for(int i=0;i<G.vexnum;++i)  //可能存在图不连通的情况,若图不连通,则从一个结点出发并不能访问到所有结点,所以我们需要遍历visited表来找出尚未被访问的结点
        if(!visited[i])
            BFS(G,i);
}

void BFS(Graph G,int v){
    visit(v);
    visited(v)=true;
    EnQuene(Q,v);   //访问v结点,并将v结点入队
    while(!QueneEmpty){
        DeQuene(Q,v);  //将v结点出队
        for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w)
            //检测v所有邻接点
            if(!visited[w]){
                visit(w);  //访问w
                visited[w]=true; //将w设置为已访问
                EnQuene(Q,w); //将w入队
        	}
    }
}
算法分析

邻接矩阵存储的图的时间复杂度:

  • 邻接矩阵存储的图:访问|V|个顶点需要O(|V|)的时间
  • 查找每个顶点的邻接点都需要O(|V|)的时间
  • 时间复杂度=O(|V|2)

邻接表存储的图的时间复杂度

  • 访问|V|个顶点需要O(|V|)的时间
  • 查找各个顶点的邻接点共需要O(|E|)的时间
  • 时间复杂度=O(|E|+|V|)

深度优先遍历(DFS)

算法要点

类似于树的先根遍历

  • 空间开销主要来自于函数调用栈
  • 从一个结点找到与之邻接的其他结点
  • visited数组防止重复访问
  • 如何处理非连通图
算法实现

在这里插入图片描述

bool visited[MAX_VERTEX_NUM]; //访问标记数组
void DFSTraverse(Graph G){
    for(int v=0;v<G.vexnum;v++)
        visited[v]=false;  //初始化标记数组
    for(int v=0;v<G.vexnum;v++)
        if(!visited(v))
            DFS(G,v);
}

void DFS(Graph G,int v){
    visit(v);  // 从顶点v出发,深度优先遍历图G
    visited[v]=true;  //访问顶点v
    for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w))
        if(!visited[w]) //w为u的尚未访问的邻接顶点
            DFS(G,w);
}
算法分析

空间复杂度:O(|V|)(主要来自于函数递归调用栈)

时间复杂度:邻接表=O(|V|+|E|)

​ 邻接矩阵=O(|V|2)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值