数据结构第7章 图

图的定义和术语

G r a p h = ( V , E ) Graph=(V,E) Graph=(V,E)
V:顶点(数据元素)的有穷非空集合;
E:边的有穷集合。
在图G中,如果代表边的顶点对是无序的,则称G为无向图。用圆括号序偶表示无向边。如果表示边的顶点对是有序的,则称G为有向图。用尖括号序偶表示有向边。

在这里插入图片描述

端点和邻接点
无向图:若存在一条边(i,j),则顶点i和顶点j为端点,它们互为邻接点。
有向图:若存在一条边<i,j>,则顶点i为起始端点(简称为起点),顶点j为终止端点(简称终点),它们互为邻接点。
关联(依附)
存在 ( v i , v j ) / < v i , v j > (v_i, v_j)/ <v_i, v_j> (vi,vj)/<vi,vj>, 则称该边/弧关联于顶点 v i v_i vi v j v_j vj
顶点v的度TD(v)入度ID(v)出度OD(v)
无向图:以顶点 i 为端点的边数称为该顶点的度。
有向图:以顶点i为终点的入边的数目,称为该顶点的入度。以顶点i为始点的出边的数目,称为该顶点的出度。一个顶点的入度与出度的和为该顶点的度。
完全图
无向图:每两个顶点之间都存在着一条边,称为完全无向图, 包含有n(n-1)/2条边。
有向图:每两个顶点之间都存在着方向相反的两条边,称为完全有向图,包含有n(n-1)条边。
子图
设有两个图G=(V,E)和G’=(V’,E’),若V’是V的子集,且E’是E的子集,则称G’是G的子图。

路径长度是指一条路径上经过的边的数目。
若一条路径上除开始点和结束点可以相同外,其余顶点均不相同,则称此路径为简单路径
若一条路径上的开始点与结束点为同一个顶点,则此路径被称为回路或环。开始点与结束点相同的简单路径被称为简单回路或简单环

连通、连通图和连通分量(无向图)
连通:若从顶点i到顶点j有路径,则称顶点i和j是连通的。
连通图:若图中任意两个顶点都连通,则称为连通图,否则称为非连通图。
连通分量:无向图G中的极大连通子图称为G的连通分量。
极大连通子图:该子图是 G 连通子图,将G 的任何不在该子图中的顶点加入,子图不再连通。
强连通图和强连通分量(有向图)
连通:若从顶点i到顶点j有路径,则称从顶点i到j是连通的。
强连通图:若图G中的任意两个顶点i和j都连通,即从顶点i到j和从顶点j到i都存在路径,则称图G是强连通图。

图的存储结构

邻接矩阵表示法

设G=(V,E)是具有n(n>0)个顶点的图,顶点的编号依次为0~n-1。
G的邻接矩阵A是n阶方阵,定义为:
A [ i ] [ j ] = { 1 ,  如果  < i , j > ∈ E  或者  ( i , j ) ∈ E 0 ,  否则  A [i][j]=\left\{\begin{array}{ll}1, & \text { 如果 }<i, j>\in E \text { 或者 }(i, j) \in E \\ 0, & \text { 否则 }\end{array}\right. A[i][j]={1,0, 如果 <i,j>E 或者 (i,j)E 否则 
分析1:无向图的邻接矩阵是对称的;
分析2:顶点i 的度=第 i 行 (列) 中1 的个数;
特别:完全图的邻接矩阵中,对角元素为0,其余1。

有向图的邻接矩阵
第i行含义:以结点vi为尾的弧(即顶点i的出边);
第i列含义:以结点vi为头的弧(即顶点i的入边)。
分析1:有向图的邻接矩阵不一定是对称的。
分析2:顶点i的出度 = 第i行元素之和
顶点i的入度 = 第i列元素之和
顶点i的度 = 第i行元素之和+第i列元素之和

邻接表表示法

对图中每个顶点i建立一个单链表,将顶点i的所有邻接点链起来。有向图的邻接表可以只存出边或只存入边。

邻接矩阵与邻接表表示法的关系

  1. 联系:邻接表中每个链表对应于邻接矩阵中的一行,链表中结点个数等于一行中非零元素的个数。
  2. 区别
    ① 对于任一确定的无向图,邻接矩阵是唯一的(行列号与顶点编号一致),但邻接表不唯一(链接次序与顶点编号无关)。
    ② 邻接矩阵的空间复杂度为O(n2),而邻接表的空间复杂度为O(n+e)。
  3. 用途:邻接矩阵多用于稠密图;而邻接表多用于稀疏图

图的遍历

深度优先搜索( DFS ——Depth First Search)

深度优先遍历过程:

  1. 从图中某个初始顶点v出发,首先访问初始顶点v。
  2. 依次从所有与顶点v相邻且没被访问过的顶点w出发进行深度优先搜索。

基于邻接矩阵的DFS算法

void DFS(MGraph G, int v)
{      // 以顶点v为起点深度优先遍历图G,图G采用邻接矩阵存储 
  cout<<v;  visited[v] = 1;  		//访问第v个顶点
  for(int w = 0; w< G.vexnum; w++)  //依次检查邻接矩阵v所在的行  
        if((G.arcs[v][w]!=0) && (!visited[w])) //w是v的邻接点,如果w未访问,则递归调用DFS 
            DFS(G, w);       
} 

基于邻接表的DFS算法的实现

void DFS(ALGraph G, int v)
{    //以顶点v为起点深度优先遍历图G,图G为邻接表类型 
    cout<<v;  visited[v] = 1;          //访问第v个顶点
    ArcNode *p= G.adjlist[v].firstarc; //p指向v的边链表的第一个边结点 
    while(p!=NULL) //边结点非空 
    {     
        w=p->adjvex;               	      //表示w是v的邻接点 
        if(!visited[w])  
            DFS(G, w); 	     //如果w未访问,则递归调用DFS 
        p=p->nextarc;                 //p指向下一个边结点 
    } 
} 

用邻接矩阵来表示图,遍历图中每一个顶点都要从头扫描该顶点所在行,时间复杂度为 O ( n 2 ) O(n^2) O(n2)
用邻接表来表示图,虽然有 2e 个表结点,但只需扫描 e 个结点即可完成遍历,加上访问 n个头结点的时间,时间复杂度为O(n+e)。

广度优先搜索( BFS——Breadth First Search)

广度优先遍历的过程:

  1. 访问初始点v,v入队;
  2. 出队一个节点记为w,访问w的每个临节点p,将p入队;
  3. 若队列为空,退出,否则返回步骤2;

基于邻接表的BFS算法的实现

void BFS(ALGraph G,int v)
{        
    int w, i;
    ArcNode *p;
    SqQueue *qu;		//定义环形队列指针
    InitQueue(qu);		//初始化队列
    int visited[MAXV];            	//定义顶点访问标记数组
    for (i=0;i<G.vexnum;i++) 
        visited[i]=0;	  	//访问标记数组初始化
    printf("%2d",v); 		//输出被访问顶点的编号
    visited[v]=1;              	//置已访问标记
    enQueue(qu,v);
    while (!QueueEmpty(qu))       	//队不空循环
    {	deQueue(qu,w);		//出队一个顶点w
        p=G.adjlist[w].firstarc; 	//指向w的第一个邻接点
        while (p!=NULL)		//查找w的所有邻接点
        {   if (visited[p->adjvex]==0) 	//若当前邻接点未被访问
            {	printf("%2d",p->adjvex);  //访问该邻接点
                visited[p->adjvex]=1;	//置已访问标记
                enQueue(qu,p->adjvex);	//该顶点进队
            }
            p=p->nextarc;              	//找下一个邻接点
        }
    }
    printf("\n");
}

有向无环图及其应用

最短路径

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值