第十七次-图(二)

若无向图G=(V,E)中含7个顶点,则保证图G在任何情况下都是连通的,则需要的边数最少是( ) c
A :6 B:15 C:16 D:21
分析:要想保证在任何情况下都连通,其中6个顶点组成完全图。包含6个顶点的完全图中包含6*5/2=15个条边。第7个顶点和其他6个顶点之间有一条边,就能保证图是联通的。因此,至少需要16条边
图的抽象数据类型定义
ADT Graph
Data
顶点的有穷非空集合和边的集合
Operation
InitGraph
前置条件:图不存在
输入:无
功能:图的初始化
输出:无
后置条件:构造一个空的图
DFSTraverse
前置条件:图已存在
输入:遍历的起始顶点v
功能:从顶点v出发深度优先遍历图
输出:图中顶点的一个线性排列
后置条件:图保持不变
BFSTraverse
前置条件:图已存在
输入:遍历的起始顶点v
功能:从顶点v出发广度优先遍历图
输出:图中顶点的一个线性排列
后置条件:图保持不变
DestroyGraph
前置条件:图已存在
输入:无
功能:销毁图
输出:无
后置条件:释放图所占用的存储空间
GetVex
前置条件:图已存在
输入:顶点v
功能:在图中查找顶点v的数据信息
输出:顶点v的数据信息
后置条件:图保持不变
endADT
图的遍历操作
图的遍历是从图中某一顶点出发,对图中所有顶点访问一次且仅访问一次。
抽象操作,可以是对结点进行的各种处理,这里简化为输出结点的数据

需要解决的关键问题:

  1. 在图中,如何选取遍历的起始顶点?
    从编号小的顶点开始
    在线性表中,数据元素在表中的编号就是元素在序列中的位置,因而其编号是唯一的;
    在树中,将结点按层序编号,由于树具有层次性,因而其层序编号也是唯一的;
    在图中,/任何两个顶点之间都可能存在边,顶点是没有确定的先后次序的,所以,顶点的编号不唯一。/
    为了定义操作的方便,将图中的顶点按任意顺序排列起来,比如,按顶点的存储顺序。
    2.从某个起点始可能到达不了所有其它顶点,怎么办?
    多次调用从某顶点出发遍历图的算法
    下面仅讨论从某顶点出发遍历图的算法。
    3.因图中可能存在回路,某些顶点可能会被重复访问,那么如何避免遍历不会因回路而陷入死循环?
    附设访问标志数组visited[n]
    4.在图中,一个顶点可以和其它多个顶点相连,当这样的顶点访问过后,如何选取下一个要访问的顶点?
    深度优先遍历和广度优先遍历

  2. 深度优先遍历 (DFS:Depth First Search)
    基本思想:
    ⑴ 访问顶点v;
    ⑵ 从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;
    ⑶ 重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。

  3. 广度优先遍历 (BFS:Broad First Search ;FIFO: First In First Out)
    基本思想:
    ⑴ 访问顶点v;
    ⑵ 依次访问v的各个未被访问的邻接点v1, v2, …, vk;
    ⑶ 分别从v1,v2,…,vk出发依次访问它们未被访问的邻接点,并使“先被访问顶点的邻接点”先于“后被访问顶点的邻接点”被访问。直至图中所有与顶点v有路径相通的顶点都被访问到。

6.2 图的存储结构及实现

是否可以采用顺序存储结构存储图?
图的特点:顶点之间的关系是m:n,即任何两个顶点之间都可能存在关系(边),无法通过存储位置表示这种任意的逻辑关系,所以,图无法采用顺序存储结构。
如何存储图?
考虑图的定义,图是由顶点和边组成的,分别考虑如何存储顶点、如何存储边
邻接矩阵(数组表示法)
基本思想:
用一个一维数组存储图中顶点的信息
用一个二维数组(称为邻接矩阵)存储图中各顶点之间的邻接关系
假设图G=(V,E)有n个顶点,则邻接矩阵是一个n×n的方阵,定义为:
arc[i][j]= 1 若(vi, vj)∈E(或<vi, vj>∈E)
0 其它
无向图的邻接矩阵
特点:主对角线为 0 且一定是对称矩阵
如何求顶点i的度?
邻接矩阵的第i行(或第i列)非零元素的个数
如何判断顶点 i 和 j 之间是否存在边?
测试邻接矩阵中相应位置的元素arc[i][j]是否为1
如何求顶点 i 的所有邻接点
将数组中第 i 行元素扫描一遍,若arc[i][j]为1,则顶点 j 为顶点 i 的邻接点
有向图的邻接矩阵一定不对称吗
不一定,例如有向完全图
有向图的邻接矩阵
如何求顶点 i 的出度
邻接矩阵的第 i 行元素之和
如何求顶点 i 的入度?
邻接矩阵的第 i 列元素之和
如何判断从顶点 i 到顶点 j 是否存在边?
测试邻接矩阵中相应位置的元素arc[i][j]是否为1
网图的邻接矩阵
arc[i][j]=权重 若(vi, vj)∈E(或<vi, vj>∈E)
0 若i==j
∞ 其他
邻接矩阵存储无向图的类

const int MaxSize=10; 
template <class T>
class Mgraph{
   public:
      MGraph(T a[ ], int n, int e );   
       ~MGraph( )
       void DFSTraverse(int v); 
       void BFSTraverse(int v);
        ……
   private:
       T vertex[MaxSize]; 
       int arc[MaxSize][MaxSize]; 
       int vertexNum, arcNum; 
};

网图:带权的图
邻接矩阵中图的基本操作——构造函数MGraph(T a[ ], int n, int e );
1.确定图的顶点个数和边的个数;
2. 输入顶点信息存储在一维数组vertex中;
3. 初始化邻接矩阵;
4. 依次输入每条边存储在邻接矩阵arc中;
4.1 输入边依附的两个顶点的序号i, j;
4.2 将邻接矩阵的第i行第j列的元素值置为1;
4.3 将邻接矩阵的第j行第i列的元素值置为1

template <class T>
MGraph::MGraph(T a[ ], int n, int e) {
    vertexNum=n; arcNum=e;
    for (i=0; i<vertexNum; i++) 
        vertex[i]=a[i];
    for (i=0; i<vertexNum; i++)    //初始化邻接矩阵
	   for (j=0; j<vertexNum; j++)
           arc[i][j]=0;             
    for (k=0; k<arcNum; k++) {
        cin>>i>>j;     //边依附的两个顶点的序号
        arc[i][j]=1;  arc[j][i]=1;  //置有边标志    
    }
}

理解:初始化 将所有值都置为一,然后自己输入不为一的边的两个顶点
n:顶点 e:边

深度优先访问:
⑴ 访问顶点v;
⑵ 从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;
⑶ 重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。
递归定义

int visited[MaxSize];
template <class T>
void MGraph::DFSTraverse(int v)  
{
     cout<<vertex[v]; visited [v]=1;
     for (j=0; j<vertexNum; j++)
         if (arc[v][j]==1 && visited[j]==0)
           DFSTraverse( j );
}

⑴ 访问顶点v;
⑵ 依次访问v的各个未被访问的邻接点v1, v2, …, vk;
⑶ 分别从v1,v2,…,vk出发依次访问它们未被访问的邻接点,并使“先被访问顶点的邻接点”先于“后被访问顶点的邻接点”被访问。直至图中所有与顶点v有路径相通的顶点都被访问到。

int visited[MaxSize];
template <class T>
void MGraph::BFSTraverse(int v){     
    front=rear=-1;   //假设采用顺序队列且不会发生溢出
   int Q[MaxSize]; cout<<vertex[v]; visited[v]=1;  Q[++rear]=v; 
    while (front!=rear)    {
         v=Q[++front];   
         for (j=0; j<vertexNum; j++)
            if (arc[v][j]==1 && visited[j]==0 ) {
                  cout<<vertex[j]; visited[j]=1; Q[++rear]=j;
            }
      }
}
//不太理解 还要回头再看一看

增加一个顶点
在存储顶点的一维数组中插入该顶点的信息
在邻接矩阵中插入一行、一列
删除一个顶点
在存储顶点的一维数组中删除该顶点的信息
在邻接矩阵中删除一行、一列
增加一条边
修改相应的矩阵元素的值
删除一条边
修改相应的矩阵元素的值
增加一个顶点:

template <class T>
void MGraph<T>::InsertVex(int num,T name) { 
 if ( num<0|| num>vertexNum) throw "位置";     
 int row, col, numv; 
 numv = vertexNum-1;
vertexNum++;    
for(int i=numv;i>=num;i--)	vertex[i++]=vertex[i];  
vertex[num]=name;    
 for(row=numv;row>=0;row--)  {所有行上num列之后的列后移,增加一列,
    for(col=numv;col>=num;col--)  arc[row][col+1]=arc[row][col];
     arc[row][num]=0;
  }
  for(row=numv;row>=num;row--) 
        for(col=0;col<=numv+1;col++)  arc[row+1][col]=arc[row][col];	
  for(col=0;col<vertexNum;col++)  arc[num][col]=0; 
 }

删除一个顶点:

template <class T>   void MGraph<T>::DeleteVex(int pos){
     if ( pos<0||  pos>MaxSize) throw "位置";   
     int row, col;    
     int numv=vertexNum;    
     for(int i=pos;i<numv;i++)   vertex[i]=vertex[i+1];    
     vertexNum--;                            
     for(row=0;row<numv;row++)   { //删除一列
         for(col=pos;col<numv;col++)	  arc[row][col]=arc[row][col+1];  
    }
    for(row=pos;row<numv;row++) 
	  for(col=0;col<numv;col++)
		  arc[row][col]=arc[row+1][col];      
  } 
}

插入一条边:

template <class T>
void MGraph<T>::InsertArc(int i, int j)
{
  if ( i>MaxSize||  j>MaxSize) throw "位置";  
  arc[i][j]=1;
  arc[j][i]=1;
} 

删除一条边:

template <class T>
void MGraph<T>::DeleteArc(int i, int j)
{
         if ( i>MaxSize||  j>MaxSize) throw "位置";
 
         arc[i][j]=arc[j][i]=0;   
}

邻接表:
图的邻接矩阵存储结构的空间复杂度?
如果为稀疏图则会出现什么现象?
假设图G有n个顶点e条边,则存储该图需要O(n2)
邻接表存储的基本思想:
对于图的每个顶点vi,将所有邻接于vi的顶点链成一个单链表,称为顶点vi的边表(对于有向图则称为出边表)
所有边表的头指针和存储顶点信息的一维数组构成了顶点表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值