【数据结构】 图的邻接表

article/2025/8/27 19:47:08

邻接表是图的另一种存储结构(使用链表的思想)。

该方式的基本思路:顶点表后指向邻接表,邻接表中依次为当前顶点的邻接点

准备工作

与邻接矩阵类似,在构造邻接表之前,需要存储各个顶点的信息,在这里使用结构体存储。因此,在构造邻接表之前,需要先定义两个结构体:邻接表结构体、顶点结构体。【其中,都需要用到指向邻接表的指针!】

struct EdgeNode{		//邻接表 int ad;				//记录邻接点的位置 EdgeNode *next;		//指向邻接表的指针
};
struct VertxNode{		//顶点表 char vertx;EdgeNode *firstEdge;//指向邻接表的指针
};

类的声明

与邻接矩阵类似,在这里,继续使用C++面向对象的方法完成构建。

class AlGraph{
public:AlGraph(char a[],int n,int e);	//通过顶点数据、点数、边数建邻接表 ~AlGraph();						//使用链表存储,非静态存储,需析构!void dfs(int v);				void bfs(int v);				
private:VertxNode adjlist[MaxSize];			//结构数组存放各顶点 int vertxNum,edgeNum;				//点数、边数 }; 

建表

构造函数

构造函数与单链表的头插法类似,但又不完全相同。如图,单链表中的first结点为一个结构体变量,其中包含next指针。

在实现单链表的头插法时,首先将插入元素的next指针与first指针指向同一位置,之后将头指针的next指针指向新插入的元素。而在邻接表构建中,顶点结构体就相当于单链表头插构造中的整个first结点,顶点结构体中的firstEdge指针就相当于单链表first结点的next指针!(如图所示)

【图】

邻接表的构造过程用以下代码实现:

AlGraph::AlGraph(char a[],int n,int e){vertxNum=n,edgeNum=e;int i,j,k;//顶点结构初始化(抄入顶点数据并将头指全部置空) for(i=0;i<vertxNum;i++){adjlist[i].vertx=a[i];adjlist[i].firstEdge=NULL;} //使用链表头插法,对输入的边关系挂链 EdgeNode *s=NULL;for(k=0;k<edgeNum;k++){cout << "输入边的两个顶点编号:";cin>>i>>j;			//输入顶点,i已存入顶点结构,j存入邻接点域。s=new EdgeNode;s->ad=j;			//将j挂链到i上 (头插)s->next=adjlist[i].firstEdge;adjlist[i].firstEdge=s;} 
} 

析构函数

由于邻接表使用链表存储数据,为动态存储,不同于邻接矩阵的数组存储结构。因此,需要手动写析构函数!

析构过程的思路及代码如下:

AlGraph::~AlGraph(){//使用链表存储邻接点,存储结构非静态,需循环删除指针EdgeNode *p,*q;		//工作指针p ,临时指针q(暂存被删除元素) p=NULL,q=NULL;for(int i=0;i<vertxNum;i++){p=q=adjlist[i].firstEdge;while(p){p=p->next;delete q;	//删除临时指针指向的数据 q=p; 		//更新临时指针指向 }}
} 

图的遍历

与邻接矩阵相同,有两种方式对图进行遍历:DFS、BFS。其思路与邻接矩阵时实现的思路完全一样,所不同的仅仅是对链表的遍历过程。

DFS

void AlGraph::dfs(int v){cout<<adjlist[v].vertx; vis[v]=1;//遍历邻接表EdgeNode *p=NULL;p=adjlist[v].firstEdge; 	//工作指针初始化为邻接表第一个元素 int i; while(p){i=p->ad;if(!vis[i]) dfs(i);	p=p->next;} 
}

BFS

void AlGraph::bfs(int v){//思路:用队列,将元素访问、标记、入队 int front,rear;front=rear=-1;int Q[MaxSize],j,t;		//t存储出队元素,j存储邻接点位置 cout<<adjlist[v].vertx;vis[v]=1;Q[++rear]=v;//从起点出发遍历邻接表 EdgeNode *p=NULL;	while(front!=rear){t=Q[++front];p=adjlist[t].firstEdge;		//工作指针指向顶点后第一个邻接点while(p){j=p->ad;if(!vis[j]){cout<<adjlist[j].vertx;vis[j]=1;Q[++rear]=j;}p=p->next;}	} 
}

完整代码

​ 如图,测试边为:(0 1)(0 3)(0 4)(1 2)(2 4)(3 2)(3 4)

【图】

#include<iostream>
using namespace std;
const int MaxSize=10;
int vis[MaxSize]={0};
struct EdgeNode{		//邻接表 int ad;				//记录邻接点位置 EdgeNode *next;
};
struct VertxNode{		//顶点表 char vertx;EdgeNode *firstEdge;//顶点表指向邻接表,指针为邻接表类型 
};
//思路:顶点表后指向邻接表,邻接表中依次为当前顶点的邻接点 
class AlGraph{
public:AlGraph(char a[],int n,int e);	//通过顶点数据、点数、边数建邻接表 ~AlGraph();						//使用链表存储,非静态存储,需析构!void dfs(int v);				void bfs(int v);				
private:VertxNode adjlist[MaxSize];			//结构数组存放各顶点 int vertxNum,edgeNum;				//点数、边数 }; 
AlGraph::AlGraph(char a[],int n,int e){vertxNum=n,edgeNum=e;int i,j,k;//顶点结构初始化(抄入顶点数据并将头指全部置空) for(i=0;i<vertxNum;i++){adjlist[i].vertx=a[i];adjlist[i].firstEdge=NULL;} //使用链表头插法,对输入的边关系挂链 EdgeNode *s=NULL;for(k=0;k<edgeNum;k++){cout << "输入边的两个顶点编号:";cin>>i>>j;			//输入顶点,i已存入顶点结构,j存入邻接点域。s=new EdgeNode;s->ad=j;			//将j挂链到i上 (头插)s->next=adjlist[i].firstEdge;adjlist[i].firstEdge=s;} 
} void AlGraph::dfs(int v){cout<<adjlist[v].vertx; vis[v]=1;//遍历邻接表EdgeNode *p=NULL;p=adjlist[v].firstEdge; 	//工作指针初始化为邻接表第一个元素 int i; while(p){i=p->ad;if(!vis[i]) dfs(i);	p=p->next;} 
}void AlGraph::bfs(int v){//思路:用队列,将元素访问、标记、入队 int front,rear;front=rear=-1;int Q[MaxSize],j,t;		//t存储出队元素,j存储邻接点位置 cout<<adjlist[v].vertx;vis[v]=1;Q[++rear]=v;//从起点出发遍历邻接表 EdgeNode *p=NULL;	while(front!=rear){t=Q[++front];p=adjlist[t].firstEdge;		//工作指针指向顶点后第一个邻接点while(p){j=p->ad;if(!vis[j]){cout<<adjlist[j].vertx;vis[j]=1;Q[++rear]=j;}p=p->next;}	} 
}AlGraph::~AlGraph(){//使用链表存储邻接点,存储结构非静态,需循环删除指针EdgeNode *p,*q;		//工作指针p ,临时指针q(暂存被删除元素) p=NULL,q=NULL;for(int i=0;i<vertxNum;i++){p=q=adjlist[i].firstEdge;while(p){p=p->next;delete q;	//删除临时指针指向的数据 q=p; 		//更新临时指针指向 }}
} int main( )
{char ch[ ] = {'A','B','C','D','E'};int i;AlGraph ALG(ch, 5, 7);               //建立具有5个顶点6条边的有向图for (i = 0; i < MaxSize; i++)vis[i] = 0;cout << "深度优先遍历序列是:";ALG.dfs(0);                       //从顶点0出发进行深度优先遍历cout<<endl;for (i = 0; i < MaxSize; i++)vis[i] = 0;cout << "广度优先遍历序列是:"; ALG.bfs(0);                      //从顶点0出发进行广度优先遍历return 0;
}

http://chatgpt.dhexx.cn/article/agYxqrsR.shtml

相关文章

《数据结构》-图的邻接表表示法(四)

邻接表表示法(链式) 存储定义&#xff1a; 顶点&#xff1a;按编号顺序将顶点数据存储在一维数组中关联同一顶点的边(以顶点为尾的弧)&#xff1a;用线性链表存储 无向图的邻接表 例如&#xff0c;如下无向图 则它的邻接表为 无向图邻接表的特点&#xff1a; 邻接表不唯一…

【图】邻接表

目录 无向图的邻接表 链表&#xff08;存相邻顶点下标&#xff09;的类 数组里放的顶点 邻接表&#xff08;操作&#xff09; 构造和析构&#xff08;创建销毁邻接表&#xff09; 插入顶点 插入边 获取下标 插v1、v2之间的边 删除顶点 删除边 输出&#xff1a; 其他…

图的邻接表表示法(C语言)

邻接表 邻接表数据结构类型如下&#xff1a; #define MaxVertices 100 typedef struct node{ //边表 int adjvex;node* next; }EdgeNode; typedef struct{ //顶点表 int vertex; EdgeNode* edgenext; }VertexNode; typedef VertexNode AdjList[MaxVertices];//…

邻接表的创建

邻接表 特点&#xff1a; 1、想要知道某个顶点的度&#xff0c;就去查找这个顶点的边表中结点的个数 2、若想判断顶点 Vi 到 Vj是否存在边&#xff0c;只需测试顶点 Vi 的边表中adjvex是否存在 Vj 的下标。 3、若求顶点的所有邻接点&#xff0c;其实就是对此顶点的边表进行遍历…

邻接表创建

邻接矩阵是个不错的图储存结构&#xff0c;但我们发现&#xff0c;对于边数相对顶点较少的图&#xff0c;这种结构是存在对储存空间的极大浪费的&#xff08;关于邻接矩阵的相关知识在这里&#xff1a;邻接矩阵的创建&#xff09;&#xff0c;因此我们要考虑另外一种存储结构方…

邻接表和邻接矩阵

进入图论的大门&#xff08;深渊&#xff09;之前&#xff0c;我们一定要掌握的两种必备手段——邻接表和邻接矩阵&#xff0c;此刻将成为我们的巨大帮手&#xff08;其实做不来题还是做不来&#xff09;&#xff0c;下面让我们来学习一下&#xff0c;这两种存图方式在计算机中…

图的邻接矩阵和邻接表的比较

欢迎关注“软件开发理论”公众号获取干货 图的存储结构主要分两种&#xff0c;一种是邻接矩阵&#xff0c;一种是邻接表。 1.邻接矩阵 图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息&#xff0c;一个二维数组&#xff08;邻接矩阵&#xff09;存储图…

无向图邻接表实现

无向图邻接表实现 顶点&#xff1a;按照编号顺序将顶点数据存储在一维数组当中 关联同一个顶点的边&#xff08;以顶点为尾的弧&#xff09;&#xff1a;用线性链表存储 头结点&#xff1a;datafirstarc 表结点&#xff1a;adjvex&#xff08;邻接点的序号&#xff0c;存放…

邻接矩阵和邻接表

图的存储结构主要分两种&#xff0c;一种是邻接矩阵&#xff0c;一种是邻接表。 1.邻接矩阵 邻接矩阵的存储方式是用两个数组来表示图。一个一维数组储存图中顶点信息&#xff0c;一个二维数组储存图中的边或弧的信息。 无向图 这里右图是把顶点作为矩阵内行和列的标头罗列出…

图--邻接表

邻接表是图结构中的一种存储结构&#xff0c;适用于存储无向图和有向图。 邻接表存储图的实现方式是&#xff0c;给图中的各个顶点独自建立一个链表&#xff0c;用节点存储该顶点&#xff0c;用链表中其他节点存储各自的临界点。 与此同时&#xff0c;为了便于管理这些链表&a…

邻接表的实现(有向邻接表)、(无向邻接表),基于C++

邻接表 邻接矩阵的实现请看这里 是不错的一种图存储结构&#xff0c;但是&#xff0c;对于边数相对顶点较少的图&#xff0c;这种结构存在对存储空间的极大浪费。因此&#xff0c;找到一种数组与链表相结合的存储方法称为邻接表。 邻接表的处理方法是这样的&#xff1a; &a…

邻接表图文详解

在与链表相关的诸多结构中&#xff0c;邻接表是相当重要的一个。它是树与图结构的一般化存储方式&#xff0c; 邻接表可以看成“带有索引数组的多个数据链表”构成的结构集合。在这样的结构中存储的数据被分成若干类&#xff0c;每一类的数据构成一个链表。每一类还有一个代表元…

数据结构 图的邻接表

呃&#xff0c;下面该写邻接表了....... 邻接表的出现是因为图若是稀疏图&#xff0c;用邻接矩阵会造成空间的浪费&#xff0c;毕竟你要开辟一个一维数组和一个二维数组嘛&#xff0c;而且还是大开小用的那种。 邻接表为了避免内存的浪费引入了链式存储&#xff0c;它的处理办…

怎么画邻接表?不用邻接矩阵也能画?

目录 一、有向图的邻接表 二、无向图的邻接表 一、有向图的邻接表 最简单粗暴的方式就是把某个顶点发出的箭头指向的顶点全作为单个结点连接到此顶点的后面。结点数等于边数。 按正常思路的话&#xff0c;是一种递归遍历。 1.选一个点作为出发点。比如选一个v0。 2.从第一出…

数据结构之图(三)——邻接表

邻接表表示法(链式) 顶点&#xff1a; 按编号顺序将顶点数据存储在一维数组中。关联同一顶点的边&#xff1a; 用线性链表存储。如果有边\弧的信息&#xff0c;还可以在表结点中增加一项&#xff0c; 无向图的邻接表 例子&#xff1a; 特点&#xff1a; 邻接表不唯一若无向…

邻接表

邻接表&#xff1a;所谓邻接表&#xff08;adjacency list&#xff09;&#xff0c;就是把从同一个顶点发出的边链接在同一个称为边链表的单链表中。边链表的每个结点代表一条边&#xff0c;称为边结点。每个边结点有2 个域&#xff1a;该边终点的序号&#xff0c;以及指向下一…

图的邻接表

邻接表 图的邻接表存储方法跟树的孩子链表示法相类似&#xff0c;是一种顺序分配和链式分配相结合的存储结构。如这个表头结点所对应的顶点存在相邻顶点&#xff0c;则把相邻顶点依次存放于表头结点所指向的单向链表中。如词条概念图所示&#xff0c;表结点存放的是邻接顶点在…

【数据结构】图的存储结构—邻接表

目录 什么是邻接表&#xff1f; 邻接表&#xff1a;定义 邻接表&#xff1a;相关类 邻接表&#xff1a;基本操作 1&#xff09;创建无向网 2&#xff09;创建有向网 3&#xff09;顶点定位 4&#xff09;插入边 5&#xff09;第一个邻接点 6&#xff09;查询下一个邻…

图的存储结构---邻接表

1. 邻接表&#xff08;无向图&#xff09; 对于边数相对顶点较少的图&#xff0c;可采取邻接表。把数组与链表结合在一起来存储&#xff0c;这种方式在图结构也适用&#xff0c;称为邻接表&#xff08;AdjacencyList&#xff09;。 2. 邻接表&#xff08;有向图&#xff09…

图的存储结构——邻接表

图的存储结构之邻接表 一、邻接表表示法无向图的邻接表有向图的邻接表有向图的逆邻接表 二、图的邻接表存储表示三、采用邻接表表示法创建无向网 一、邻接表表示法 回忆在线性表时&#xff0c;顺序存储结构就存在预先分配内存可能造成存储空间浪费的问题&#xff0c;于是引出了…