数据结构——图(2、图的存储结构及实现)

数据结构 专栏收录该内容
12 篇文章 0 订阅

图的存储结构及实现

邻接矩阵(数组表示法)

存储基本思想
用一个一维数组存储图中顶点的信息
用一个二维数组(称为***邻接矩阵***)存储图中各顶点之间的邻接关系。
假设图G=(V,E)有n个顶点,则邻接矩阵是一个n×n的方阵,定义为:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

邻接矩阵存储无向图的类

代码实现

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;  //置有边标志    
    }
}

邻接矩阵中图的基本操作——深度优先遍历

⑴ 访问顶点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 );
}
  • 采用深度优先搜索方法解决迷宫问题
bool end=false;bool find=false;
search(int x,int y){
	int new_x,new_y;	
	if (x==out_x && y==out_y)	{
		end=true;
	}
	else{
	       for(int i=0;i<=3;i++){
  	        if(!end){
		new_x=x+nx[i];	new_y=y+ny[i];
   		if(maze[new_x][new_y]==0 && trace[new_x][new_y]==0)
		{
			trace[new_x][new_y]=1;
  			search(new_x,new_y);
			if (end) cout<<"("<<new_x<<","<<new_y<<")"<<endl;
		}
	       }
	   }
	}  
 }

邻接矩阵中图的基本操作——广度优先遍历

⑴ 访问顶点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];      
  } 
}

增加一条边

修改相应的矩阵元素的值
在这里插入图片描述

tmplate <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;   
}

邻接表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 有向图的逆邻接表(入边表)
    在这里插入图片描述

邻接表存储有向图的类

const int MaxSize=10;    //图的最大顶点数
template <class T>
class ALGraph
{    
   public:
       ALGraph(T a[ ], int n, int e);   
       ~ALGraph;    
       void DFSTraverse(int v);      
       void BFSTraverse(int v);      
   ………
  private:
       VertexNode adjlist[MaxSize];   
       int vertexNum, arcNum;       
};

邻接表中图的基本操作——构造函数

  1. 确定图的顶点个数和边的个数;
  2. 输入顶点信息,初始化该顶点的边表;
  3. 依次输入边的信息并存储在边表中;
    3.1 输入边所依附的两个顶点的序号i和j;
    3.2 生成邻接点序号为j的边表结点s;
    3.3 将结点s插入到第i个边表的头部;
template <class T>
ALGraph::ALGraph(T a[ ], int n, int e)
{   
    vertexNum=n; arcNum=e; 
    for (i=0; i<vertexNum; i++)   
    {
       adjlist[i].vertex=a[i];
       adjlist[i].firstedge=NULL;      
    } 
   
    for (k=0; k<arcNum; k++)   
    {
        cin>>i>>j;    
        s=new ArcNode; s->adjvex=j;  	        
        s->next=adjlist[i].firstedge;    
        adjlist[i].firstedge=s;
    }
}

邻接表中图的基本操作——深度优先遍历

template <class T>
void ALGraph::DFSTraverse(int v){        
    cout<<adjlist[v].vertex;  visited[v]=1;
    p=adjlist[v].firstedge;    
    while (p!=NULL)     {
        j=p->adjvex;
        if (visited[j]==0) DFSTraverse(j);
    p=p->next;           
    }
}

在这里插入图片描述

邻接表中图的基本操作——广度优先遍历

template <class T>
void ALGraph::BFSTraverse(int v){
   front=rear=-1;   
   cout<<adjlist[v].vertex;    visited[v]=1;   Q[++rear]=v;   
   while (front!=rear)  {
       v=Q[++front];    p=adjlist[v].firstedge;    
       while (p!=NULL)  {
            j= p->adjvex;
            if (visited[j]==0) {
                cout<<adjlist[j].vertex;  visited[j]=1; Q[++rear]=j;
            }
            p=p->next;
       }
    }
}

在这里插入图片描述

增删顶点

增加:顶点表中插入一个元素
删除:在顶点表中删除一个元素,同时在边表中删除相应的边

增删边<x, y>

如果是有向图,则在x的边表中增加/删除边;
如果是无向图,则还要在y的边表中增加/删除一条边

图的存储结构的比较——邻接矩阵和邻接表

在这里插入图片描述

图的存储补充

  • 邻接矩阵
    有向图和无向图
  • 邻接表
    有向图(出边表)和无向图
  • 逆邻接表(有向图的入边表)
    有向图,方便计算顶点的入度
  • 有向图的十字链表
  • 无向图的邻接多重表
  • 边集数组
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 1024 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值