图的存储结构——邻接表

article/2025/8/27 22:18:53

图的存储结构之邻接表

  • 一、邻接表表示法
    • 无向图的邻接表
    • 有向图的邻接表
    • 有向图的逆邻接表
  • 二、图的邻接表存储表示
  • 三、采用邻接表表示法创建无向网

一、邻接表表示法

回忆在线性表时,顺序存储结构就存在预先分配内存可能造成存储空间浪费的问题,于是引出了链式存储结构,同样的,我们可以考虑对边或弧使用链式存储方式来避免空间浪费问题

邻接表是图的一种链式存储结构。

由两部分组成:表头结点表和边表

邻接表中每个单链表的第一个结点存放有关顶点的信息,把这一结点看成链表的表头,其余结点存放有关边的信息

(1)表头结点表:包括数据域和链域,数据域存储顶点的名称,链域用于指向链表中第一个结点(与顶点邻接的第一个顶点)

(2)边表:包括邻接点域(指示与顶点邻接的点在图中的位置,即数组下标)、数据域(存储和边相关的信息,如权值)、链域(指示与顶点邻接的下一条边的结点)

表头结点表:
在这里插入图片描述
边表:
在这里插入图片描述

无向图的邻接表

在这里插入图片描述

特点:

  1. 邻接表不唯一(边表顺序可以互换)
  2. 无向图中有n个顶点、e条边,则其邻接表需n个头结点和2e个边结点,复杂度为O(n+2e)<O(n^2),所以适合存储稀疏图
  3. 无向图中顶点Vi的度为第i个单链表中的结点数。

有向图的邻接表

在这里插入图片描述
特点:

  1. 顶点vi的出度为第i个单链表中的结点个数
  2. 顶点vi的入度为整个单链表中邻接点域值是i-1的结点个数(需要遍历整个整个邻接表,较麻烦)。

为了便于确定顶点的入度,可以建立一个有向图的逆邻接表,即对每个顶点vi建立一个链接所以进入vi的边的表

有向图的逆邻接表

与上图同步

在这里插入图片描述
特点:

  1. 顶点vi的入度为第i个单链表中的结点个数
  2. 顶点vi的出度为整个单链表中邻接点域值是i-1的结点个数

此时我们很容易就可以算出某个顶点的入度或出度是多少,判断两顶点是否存在弧也很容易实现。

二、图的邻接表存储表示

//边的结点结构
#define MVNum 100 //最大顶点数
typedef struct ArcNode{int adjvex;  //该边所指向的顶点的位置 struct ArcNode *nextarc;//指向下一条边的指针 Otherinfo info;  //和边相关的信息 
}ArcNode;//顶点的结点结构 
typedef struct VNode{VerTexType data;//顶点信息、ArcNode *firstarc;//指向第一条依附该顶点的边的指针 
}VNode,AdjList[MVNum];//AdjList表示邻接表类型//图的结构定义 
typedef struct{AdjList vertices; //定义一个数组vertices,是vertex的复数形式int vexnum,arcnum; //图的当前顶点数和弧数
}ALGraph;

三、采用邻接表表示法创建无向网

//创建无向图G 
bool CreateUDG(ALGraph &G){ int i,j,k,v1,v2;cin>>G.vexnum>>G.arcnum;//输入总顶点数,总边数for(i=0;i<G.vexnum;i++){//输入各顶点,构造表头结点表 cin>>G.vertices[i].data;//输入顶点值 G.vertices[i].firstarc=NULL;//初始化表头结点的指针域}//for//输入各边,构造邻接表for(k=0;k<G.arcnum;k++){cin>>v1>>v2;    //输入一条边依附的两个顶点 i=LocateVex(G,v1);j=LocateVex(G,v2); //确定顶点在G.vertices中的序号ArcNode *p1=new ArcNode;  //生成一个新的边结点*p1p1->adjvex=j;  //邻接点序号为j //头插法将新结点*p1插入顶点vi的边表头部 p1->nextarc=G.vertices[i].firstarc;G.vertices[i].firstarc=p1; ArcNode *p2=new ArcNode;p2->adjvex=i;  //邻接点序号为i//头插法插入p2 ,因为是无向网,所以是两条 p2->nextarc=G.vertices[i].firstarc;G.vertices[i].firstarc=p2; }//forreturn true; 
}//CreateUDG

算法时间复杂度是O(n+e);

int LocateVex(ALGraph G,VerTexType u){//在图G中查找顶点u,存在则返回顶点表中的下标;否则返回-1int i;for(i=0;i<G.vexnum;i++)if(u==G.vertices[i])return i;return -1;
} 

注意:一个图的邻接矩阵表示是唯一的,但其邻接表表示不唯一,这是因为邻接表表示中,各边表结点的链接次序取决于建立邻接表的算法,以及边的输入次序

代码实现此邻接表:

在这里插入图片描述

#include<iostream>
#include<queue>
using namespace std; 
#define MVNum 100 //最大顶点数typedef struct ArcNode{int adjvex;  //该边所指向的顶点的位置 struct ArcNode *nextarc;//指向下一条边的指针 
}ArcNode;//顶点的结点结构 
typedef struct VNode{char data;//顶点信息、ArcNode *firstarc;//指向第一条依附该顶点的边的指针 
}VNode,AdjList[MVNum];//AdjList表示邻接表类型//图的结构定义 
typedef struct{AdjList vertices; //定义一个数组vertices,是vertex的复数形式int vexnum,arcnum; //图的当前顶点数和弧数
}ALGraph;int LocateVex(ALGraph G,int u){//在图G中查找顶点u,存在则返回顶点表中的下标;否则返回-1int i;for(i=1;i<=G.vexnum;i++)if(u == G.vertices[i].data)return i;return -1;
} //创建无向图G 
bool CreateUDG(ALGraph &G){ cout << "请输入总结点数和总边数:" << endl; cin>>G.vexnum>>G.arcnum;//输入总顶点数,总边数cout << " 输入各顶点值: " << endl; for(int i = 1;i <= G.vexnum;i++){//输入各顶点,构造表头结点表 cin>>G.vertices[i].data;//输入顶点值 G.vertices[i].firstarc=NULL;//初始化表头结点的指针域}//forgetchar();//输入各边,构造邻接表cout << "输入一条边依附的两个顶点值"<<endl; for(int k=1;k<=G.arcnum;k++){char v1,v2;cin>>v1>>v2;    //输入一条边依附的两个顶点 getchar();int i=LocateVex(G,v1);int j=LocateVex(G,v2); //确定顶点在G.vertices中的序号ArcNode *p1=new ArcNode;  //生成一个新的边结点*p1p1->adjvex=j;  //邻接点序号为j //头插法将新结点*p1插入顶点vi的边表头部 p1->nextarc=G.vertices[i].firstarc;G.vertices[i].firstarc=p1; ArcNode *p2=new ArcNode;p2->adjvex=i;  //邻接点序号为i//头插法插入p2 ,因为是无向网,所以是两条 p2->nextarc=G.vertices[j].firstarc;G.vertices[j].firstarc=p2; }//forreturn true; 
}//CreateUDGint main()
{ALGraph G;ArcNode *p;CreateUDG(G);cout << "输出邻接表: " <<endl;for(int i = 1; i<= G.vexnum; i++){cout << G.vertices[i].data;for(p = G.vertices[i].firstarc; p != NULL; p = p->nextarc)printf("->%d", p->adjvex);cout << endl; } return 0;
}

在这里插入图片描述

邻接表表示法优缺点:
(1)优点

  1. 便于增加和删除顶点。
  2. 便于统计边的数目,时间复杂度是O(n+e)
  3. 空间效率高

(2)缺点

  1. 不便于判断顶点之间是否有边
  2. 不便于计算有向图各顶点的度

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

相关文章

vivado实现FFT和IFFT信号处理

一&#xff0c;FFT的物理意义 FFT是离散傅立叶变换的快速算法&#xff0c;可以将一个信号变换到频域。有些信号在时域上是很难看出什么特征的&#xff0c;但是如果变换到频域之后&#xff0c;就很容易看出特征了。这就是很多信号分析采用FFT变换的原因。另外在频谱分析方面&a…

ifft java_OpenCV DFT_INVERSE与Matlab的ifft不同

我尝试使用opencv的dft函数过滤信号 . 我试图这样做的方式是在时域中获取信号&#xff1a; x [0.0201920000000000 -0.0514940000000000 0.0222140000000000 0.0142460000000000 -0.00313500000000000 0.00270600000000000 0.0111770000000000 0.0233470000000000 -0.00162700…

4.8 IFFT/FFT

4.8.1 IFFT/FFT原理 1. IFFT、FFT在OFDM系统中的应用 2、IFFT/FFT原理 3、DIT的基2FFT算法 4、DIF的基2FFT运算 5、基于的频率抽选FFT算法 4.8.2 基于 DIF FFT的硬件 结构 1、各级的蝶形运算硬件实现 2、transfer12、 transfer34、transfer56硬件实现 3、transfer23、 transfe…

Python实现FFT及IFFT

运行环境及编译工具 WindowsVS Code 编程语言及库版本 库版本Python3.7.0copy无numpy1.19.2opencv3.4.2PIL8.1.0matplotlib3.4.3 可执行文件 HW_2.pyHW_2.ipynb在HW_2.ipynb中执行&#xff0c;详细程序信息在HW_2.py中 问题 1 通过计算一维傅里叶变换实现图像二维快速傅里…

matlab FFT 和IFFT

代码&#xff1a; fs100;N128; n0:N-1;tn/fs; xsin(2*pi*40*t)sin(2*pi*15*t); subplot(221);plot(n,x,b); xlabel(时间/s);ylabel(x);title(原始信号); grid on;yfft(x,N); magabs(y); fn*fs/N; subplot(222);plot(f(1:N/2),mag(1:N/2)*2/N,b); xlabel(频率/Hz);ylabel(振幅)…

基于vivado实现FFT/IFFT

文章目录 前言一、基本过程二、vivado配置1.新建工程2.调用DDS的IP核2.调用FFT的IP核 三、编写Verilog程序1.顶层文件fft.v2.仿真文件fft_tb.v 四、运行仿真1. 运行仿真设置2. 仿真波形设置3. 结果分析 前言 使用vivado2018.3实现FFT&#xff0f;IFFT&#xff0c;过程比较详细…

python fft ifft

文章目录 条件代码实例 条件 任何一个满足狄利克雷条件的函数都可以通过傅里叶基数展开。 numpy和scipy中都有fft变换&#xff0c;且效果都是一样的。 代码 import numpy as np from scipy.fftpack import fft,ifft import matplotlib.pyplot as plt from matplotlib.pylab …

FFT专题:IFFT后信号如何重建

ifft(outFFTData, g_fft_temp, inFFTData, g_twiddle_ifft, twiddle_stride, F_WLEN);//思考ifft输出的复数结果怎么给到硬件输出 之前一直关注FFT后信号奔赴到频域处理,那么频域处理完后,怎么重建信号呢? 给出一段FFT和IFFT函数源码 int nFrameRunCount 0;#pragma section…

数字信号处理基础(二):FFT和IFFT的使用以及详细分析代码书写思路

目录 1. fft和ifft的原理1.1 fft1.2 ifft 2. 书写代码思路3. 完整代码4. 结果图 1. fft和ifft的原理 1.1 fft fft是快速傅里叶变换&#xff0c;是MATLAB中计算信号频谱的函数&#xff0c;使用方法是fft(x)&#xff0c;直接对信号x进行fft计算。 由于fft函数计算信号的频谱是0…

信号处理中的反傅里叶变换(IFFT)原理

信号处理中&#xff0c;经常需要将信号转换到频域进行分析&#xff0c;有时候还会从频域转回时域&#xff0c;用到FFT和IFFT函数。 FFT变换是将信号从时域转换到频域&#xff0c;在时域看起来复杂的信号转换到频域看起来就方便容易了很多。但有时候也需要将频域信号转换到时域…

adb下载、安装、环境配置

一&#xff1a;adb安装 adb下载链接&#xff1a;https://pan.baidu.com/s/1Vd6KyZ6vT2Qtmhazwre4OQ 提取码&#xff1a;3dx1 安装&#xff1a; 1.双击adb.exe文件&#xff0c;并运行。 2.添加环境变量&#xff1a; 右击计算机–属性—高级系统设置—高级—环境变量—新建&…

windows下载安装adb(极其简单)

单独安装adb&#xff0c;不安装sdk 下载adb Google很好的心&#xff0c;直接放出ADB的档案供人下载。下档路径如下&#xff1a; Windows版本&#xff1a;https://dl.google.com/android/repository/platform-tools-latest-windows.zip Mac版本&#xff1a;https://dl.google…

ADB-adb命令安装app

下载adb 安装adb 将名称中含有adb的文件&#xff0c;和fastboot.exe复制到 c:/windows/system32目录将名称中含有adb的所有文件复制到 c:/windows/system目录将adb.exe和AdbWinApi.dll复制到c:/windows/SysWoW64目录 有线安装apk 连接上数据线&#xff0c;然后把手机开发者模…

adb详细教程(一)-下载安装与环境变量配置

对于Android开发来说&#xff0c;adb是再熟悉不过的调试工具 但其实对于移动端的测试来说&#xff0c;adb也是一个十分重要的、能够提高测试工作效率的工具。 文章目录 一、介绍二、下载地址三、安装四、配置环境变量 一、介绍 全称 adb全称全称为Android Debug Bridge&#x…

mac下载安装adb环境

目录 方法一1、下载安装包2、下载完成后进行解压&#xff0c;目录路径注意不得包含中文3、配置环境变量4、验证安装是否成功 方法二1、安装homebrew2、安装adb3、运行adb 方法一 1、下载安装包 安装包下载地址 &#xff1a;https://developer.android.com/studio/releases/pl…

adb工具下载安装

一、adb环境配置 adb即Android Debug Bridge&#xff0c;就是可以通过窗口命令&#xff0c;使在pc端可以调试安卓移动端的一个工具包 我这里是默认电脑已经安装SDK的&#xff0c;如果没有也没关系&#xff0c;直接网上下载一个adb工具包一样的https://developer.android.goo…

adb环境配置

adb环境配置 1.下载工具包 工具包&#xff1a;platform-tools_r30.0.4-windows.zip 获取途径1&#xff1a;链接: https://pan.baidu.com/s/17BiARFlgsQa2wDETmoJIvQ?pwddsd2 提取码: dsd2 获取途径2&#xff1a;https://developer.android.google.cn/studio/releases/plat…

android adb驱动官方下载,adb驱动下载

这里给你简单的介绍一下adb驱动:adb驱动就是电脑与android设备的通信的客户端驱动程序。使用它可以直接操作管理android模拟器或者真实的andriod设备。 adb驱动百科介绍: Android设备(如手机)连接PC时所需要的驱动程序,一般Android设备连接WinXP是无需安装驱动的。 adb的全称…

windows ——adb下载与安装

一、adb下载 链接&#xff1a;https://pan.baidu.com/s/1D3eOkHsuAnZd6WoFEVC7xQ 提取码&#xff1a;sc94 二、adb安装 双击 adb-setup-1.3.exe 安装 可以查看此安装教程[转载]&#xff1a;http://m.mz6.net/detail/4506-13.html 三、adb安装成功验证 键盘快捷键&#xff1a;Wi…

adb下载安装教程(已安装Android studio)

adb下载安装教程&#xff08;已安装Android studio&#xff09; ①找到adb.exe的绝对路径如下&#xff1a; ②将绝对路径放入环境变量path中&#xff08;绝对路径不带入adb.exe&#xff09; 右击“此电脑”>“属性”>”高级系统设置“>”环境变量“>”path“ 双…