数据结构 图的邻接表和邻接矩阵实现———c语言
图的邻接矩阵实现
逻辑结构分为两部分:V和E集合。因此,用一个一维数组存放图中所有顶点数据;用一个二维数组存放顶点间关系(边或弧)的数据,这个二维数组称为邻接矩阵。邻接矩阵又分为有向图邻接矩阵和无向图邻接矩阵
邻接矩阵(Adjacency Matrix):是表示顶点之间相邻关系的矩阵。设G=(V,E)是一个图,其中V={v1,v2,…,vn}。G的邻接矩阵是一个具有下列性质的n阶方阵:
①对无向图而言,邻接矩阵一定是对称的,而且主对角线一定为零(在此仅讨论无向简单图),副对角线不一定为0,有向图则不一定如此。
②在无向图中,任一顶点i的度为第i列(或第i行)所有非零元素的个数,在有向图中顶点i的出度为第i行所有非零元素的个数,而入度为第i列所有非零元素的个数。
③用邻接矩阵法表示图共需要n^2个空间,由于无向图的邻接矩阵一定具有对称关系,所以扣除对角线为零外,仅需要存储上三角形或下三角形的数据即可,因此仅需要n(n-1)/2个空间。
代码实现
#include "graph.h"
#include <stdlib.h>
/*
typedef char VTYPE; //顶点元素的值
typedef int ETYPE; //边的值 权重 \ 连通
enum GraphKind{DG,DN,UDG,UDN};typedef struct Arc{VTYPE beg; //边起始顶点 VTYPE end; //边结束顶点 ETYPE weight; //权重 1连通
}Arc;typedef struct MGraph{VTYPE * vexs; //存储所有顶点的值 VTYPE vexs[MAX_VEXNUM];ETYPE *matrix; //ETYPE matrix[MAX_VEXNUM][MAX_VEXNUM];size_t vexnum;size_t arcnum;GraphKind kind;
}MGraph;
*/
//通过顶点的值查找该顶点所在的下标位置
static int find_vexs_index(MGraph *pg,VTYPE val){size_t i;for(i=0;i<pg->vexnum;i++){if(pg->vexs[i] == val){return i;}}return -1;
}
//MGraph g;
int graph_init(MGraph* pg,VTYPE vexs[],size_t vexnum,Arc arc[],size_t arcnum,GraphKind kind){pg->vexnum = vexnum;pg->vexs = (VTYPE*)malloc(sizeof(VTYPE)*vexnum);if(pg->vexs==NULL){return -1;}//ETYPE (*p)[vexnum];pg->matrix = (ETYPE*)malloc(sizeof(ETYPE)*vexnum*vexnum);memset(pg->matrix,0,sizeof(ETYPE)*vexnum*vexnum);if(pg->matrix==NULL){free(pg->vexs);return -1;}size_t i,j;for(i=0;i<vexnum;i++){pg->vexs[i] = vexs[i];}ETYPE (*arr)[vexnum] = (ETYPE (*)[vexnum])pg->matrix;for(i=0;i<arcnum;i++){int begi = find_vexs_index(pg,arc[i].beg);int endi = find_vexs_index(pg,arc[i].end);arr[begi][endi] = arc[i].weight;if(kind == UDG || kind == UDN){arr[endi][begi] = arc[i].weight;} }pg->arcnum = arcnum;pg->kind = kind;return 0;
}void graph_destroy(MGraph *pg){free(pg->vexs);free(pg->matrix);
}void show(MGraph* pg){printf("vex:[");size_t i,j;for(i=0;i<pg->vexnum;i++){printf("%c ",pg->vexs[i]);}printf("]\n");printf("---------------------------------------\n");printf(" ");for(i=0;i<pg->vexnum;i++){printf("%3c ",pg->vexs[i]);}ETYPE (*arr)[pg->vexnum] = (ETYPE (*)[pg->vexnum])pg->matrix;for(i=0;i<pg->vexnum;i++){printf("%3c ",pg->vexs[i]);for(j=0;j<pg->vexnum;j++){printf("%3d ",arr[i][j]);}printf("\n");}printf("\n");
}
邻接表
其实我们描述图的时候用的最多的时邻接表而不是邻接矩阵
邻接表,存储方法跟树的孩子链表示法相类似,是一种顺序分配和链式分配相结合的存储结构。如这个表头结点所对应的顶点存在相邻顶点,则把相邻顶点依次存放于表头结点所指向的单向链表中。
对于无向图来说,使用邻接表进行存储也会出现数据冗余,表头结点A所指链表中存在一个指向C的表结点的同时,表头结点C所指链表也会存在一个指向A的表结点。
图的邻接表存储方法跟树的孩子链表示法相类似,是一种顺序分配和链式分配相结合的存储结构。如这个表头结点所对应的顶点存在相邻顶点,则把相邻顶点依次存放于表头结点所指向的单向链表中。如词条概念图所示,表结点存放的是邻接顶点在数组中的索引。对于无向图来说,使用邻接表进行存储也会出现数据冗余,表头结点A所指链表中存在一个指向C的表结点的同时,表头结点C所指链表也会存在一个指向A的表结点。
邻接表是图的一种最主要存储结构,用来描述图上的每一个点。对图的每个顶点建立一个容器(n个顶点建立n个容器),第i个容器中的结点包含顶点Vi的所有邻接顶点。实际上我们常用的邻接矩阵就是一种未离散化每个点的边集的邻接表。
代码实现
#include "adjgraph.h"
/*
//邻接表存储图结构
typedef struct ArcNode{//狐结点 int adjvex; //狐头 边 邻接点所对应的下标位置 int weight; //权重 边的信息 struct ArcNode *next; //下一个狐结点
}ArcNode; typedef struct VNode{//顶点 char data; //顶点元素 A B C Dstruct ArcNode *firstarc; //第一个狐结点 从顶点出发所有的边
}VNode;typedef enum GraphKind{DG,DN,UDG,UDN}GraphKind; typedef struct ALGraph{struct VNode *vexs; //所有顶点int vexnum; //顶点数int arcnum; //狐边条数GraphKind kind; //图的类型
}ALGraph;typedef struct Edge{//边 狐 起始顶点 终点 权重 char vbeg; //起始点 char vend; //结束点 int weight; //权重
}Edge;typedef struct Path{int begi; //起始点下标 int endi; //终点下标int weight; //权重
};
*/static int graph_get_index(ALGraph *pg,char key){//通过顶点的值 查找顶点所在的下标int i;for(i=0;i<pg->vexnum;i++){if(pg->vexs[i].data == key){return i;}}return -1;
}
static ArcNode *graph_create_arcnode(int adjvex,int weight,ArcNode *next){ArcNode *node = (struct ArcNode*)malloc(sizeof(ArcNode));if(node!=NULL){node->adjvex = adjvex;node->weight = weight;node->next = next;}return node;
} //ALGraph g;
int graph_init(ALGraph *pg,char vexs[],size_t vexnum,Edge edges[],size_t arcnum,GraphKind kind){pg->vexs = (VNode *)malloc(sizeof(VNode)*vexnum);if(pg->vexs==NULL)return -1;pg->vexnum = vexnum;int i;for(i=0;i<vexnum;i++){pg->vexs[i].data = vexs[i];//顶点的值 pg->vexs[i].firstarc = NULL;//顶点没有边 }pg->arcnum = 0;pg->kind = kind;for(i=arcnum-1;i>=0;--i){graph_insert_edge(pg,edges[i]); //插入一条边 }return 0;
} void graph_destroy(ALGraph *pg){int i;for(i=0;i<pg->vexnum;i++){ArcNode *node = pg->vexs[i].firstarc,*next;while(node != NULL){next = node->next;free(node);node = next;}}free(pg->vexs);pg->vexs = NULL;pg->vexnum = 0;pg->arcnum = 0;
}
//仅测试使用
void graph_show(ALGraph *pg){int i;for(i=0;i<pg->vexnum;i++){if(pg->vexs[i].data != '\0'){printf("%c :",pg->vexs[i].data);ArcNode *node = pg->vexs[i].firstarc;for(;node!=NULL;node=node->next){printf(" [%d]%c",node->weight,pg->vexs[node->adjvex].data);}printf("\n");}}
}int graph_insert_vertex(ALGraph *pg,char key){//插入一个顶点if(graph_get_index(pg,key)>=0){//key作为顶点的值已经有了 return -1;}VNode *node = realloc(pg->vexs,sizeof(VNode)*(pg->vexnum+1));if(node==NULL){return -2;} pg->vexs = node;pg->vexs[pg->vexnum].data = key;++pg->vexnum;return 0;
}
int graph_delete_vextex(ALGraph *pg,char key){//删除一个顶点int index = graph_get_index(pg,key);if(index == -1){return -1;}pg->vexs[index].data = '\0';ArcNode *node = pg->vexs[index].firstarc,*next;while(node!=NULL){next = node->next;free(node);node = next;}int i;for(i=0;i<pg->vexnum;i++){if(pg->vexs[i].data != '\0'){ArcNode **pnode = &(pg->vexs[i].firstarc);while(*pnode != NULL){if((*pnode)->adjvex == index){node = *pnode;*pnode = node->next;free(node);break;}pnode = &(*pnode)->next;}}}return 0;
}
int graph_insert_edge(ALGraph *pg,Edge edge){//插入一条边 int ibeg = graph_get_index(pg,edge.vbeg);//获取边起始顶点下标 int iend = graph_get_index(pg,edge.vend);//获取边结束顶点下标 if(ibeg==-1 || iend==-1)//无效边 return -1; //前插法 新的边插入到最前面 A B 5//判断一条边是否存在 如果存在了 不插了 ArcNode *node = pg->vexs[ibeg].firstarc;while(node!=NULL){if(node->adjvex == iend){// ibeg->iend边已经存在了! return -3;}node = node->next;} pg->vexs[ibeg].firstarc = graph_create_arcnode(iend,edge.weight,pg->vexs[ibeg].firstarc); if(pg->vexs[ibeg].firstarc==NULL){return -2;} if(pg->kind == UDG || pg->kind == UDN){//B A pg->vexs[iend].firstarc = graph_create_arcnode(ibeg,edge.weight,pg->vexs[iend].firstarc);if(pg->vexs[iend].firstarc==NULL){node = pg->vexs[ibeg].firstarc;pg->vexs[ibeg].firstarc = node->next;free(node);return -2;}}++pg->arcnum;return 0;
}int graph_delete_edge(ALGraph *pg,Edge edge){//删除一条边 int ibeg = graph_get_index(pg,edge.vbeg); int iend = graph_get_index(pg,edge.vend);if(ibeg == -1 || iend == -1){return -1;}ArcNode **pnode = &(pg->vexs[ibeg].firstarc);ArcNode *node;bool isdel = false;while(*pnode!=NULL){if((*pnode)->adjvex == iend){node = *pnode;*pnode = node->next;free(node);isdel = true;break;}pnode = &(*pnode)->next; }if(pg->kind == UDG||pg->kind == UDN){pnode = &(pg->vexs[iend].firstarc);while(*pnode!=NULL){if((*pnode)->adjvex == ibeg){node = *pnode;*pnode = node->next;free(node);break;}}}--pg->arcnum;return isdel?0:-2;
}
数据结构 图的邻接表和邻接矩阵实现———c语言相关推荐
- 数据结构——图的邻接表存储
数据结构--图的邻接表存储 功能实现: (1)图的邻接矩阵的储存 (2)深度优先遍历 (3).广度优先遍历 (4)求结点的度 (5)判断图是否连通 (6)求最小生成树 参考代码 #include &l ...
- 图之邻接表详解(C语言版)
文章目录 一.定义 二.结构 三.常用操作 四.测试 结语 附录 一.定义 图的邻接表是一种顺序与链式存储相结合的存储方式.下面给出一个示例,以便大家能够理解邻接表这种存储方式: 无向 ...
- java邻接图_Java数据结构 - 图(邻接表存储)
邻接表 相比邻接矩阵,邻接表要更加节省空间. 邻接表存储 本文将介绍邻接表存储有向带权图.图的例子如下. 图 介绍一下邻接表 上面的图对应的邻接表如下图所示: 邻接表 前面的数组存储的是所有的顶点,每 ...
- 数据结构——图的邻接表实现
邻接矩阵需要提前预先分配空间,容易造成空间上的浪费 而且在遇到两个顶点之间没有边时,邻接矩阵是不能解决的. 邻接表的出现 是结合了数组和链表的存储方式(当然 也可以是链表+链表) 数组+链表形式的邻接 ...
- 分别用邻接矩阵和邻接表实现图的深度优先遍历和广度优先遍历_数据结构|图的邻接表与深度、广度优先搜索
线性存储元素时,元素的关系也同时确定了.而非线性数据结构就不同了,需要同时考虑存储数据元素和数据元素的关系. 由于图的结构比较复杂,任意两个顶点之间都可能存在联系,因此无法以数据元素在存储区中的物理位 ...
- 【数据结构】邻接表的储存结构 建立图的邻接表算法
[数据结构]邻接矩阵及其实现 一个图的邻接矩阵的表示是唯一的,但其邻接表表示不唯一,这是因为在邻接表结构中,各便表结点的链接次序取决于建立邻接表时的算法以及输入的次序. 一般而言邻接矩阵适合存储稠密图 ...
- 《数据结构》-图的邻接表表示法(四)
邻接表表示法(链式) 存储定义: 顶点:按编号顺序将顶点数据存储在一维数组中 关联同一顶点的边(以顶点为尾的弧):用线性链表存储 无向图的邻接表 例如,如下无向图 则它的邻接表为 无向图邻接表的特点: ...
- 【图】什么是图?无向图怎么存储?邻接表和邻接矩阵如何用代码存储图?
目录 一.概念 图是什么 各种图的定义 二.图的存储结构 邻接矩阵 邻接表 三.代码实现图的存储 1.无向图存储 2.邻接矩阵存储图 核心代码 完整代码 3.邻接表存储有向图(不含权重) 核心代码 完 ...
- 数据结构——图-有向带权图的邻接表
#include <stdio.h> #include <stdlib.h> #define VertexType char //顶点的数据类型(char) #define V ...
最新文章
- CodeOne 主题演讲:Java,未来已来
- Laravel以及Laravel-admin的命令行使用总结
- 阿里云服务器部署php的laravel项目,在阿里云买ECS 搭建 Linux+Nginx+Mysql+PHP环境的
- bzoj 1095 捉迷藏
- 忘却的旋律java2_[17-8-10]【复杂问题】打不开游戏
- TokenInsight:反映区块链行业整体表现的TI指数较昨日同期上涨5.35%
- MATLAB中常见的取整函数
- 数据结构笔记-----树
- DATEDIF函数:
- 【Netty】Netty+springboot实现IM即时通讯服务端
- VB打包时出现没有注册类,怎么解决,蟹蟹各位大神
- 关于微信小程序picker之multiSelector多列选择器
- 【python10个小实验】2、石头、剪刀、布
- mp4 转 mp3 命令行工具(超快)
- java 不生成文件下载_java – 浏览器不生成文件下载对话框
- 透明质酸/氧化石墨烯/聚丙烯酰胺复合水凝胶/透明质酸/βTCP复合水凝胶研究制备
- web前端入门到实战:css中border-style 属性
- 节能改造:空调系统节能改造方案及效果分析
- 【NIO与Netty】网络编程:netty中粘包、半包现象展示,分析及解决
- adb命令行刷机 使用adb sideload命令推送刷机包到recovery直接刷机
热门文章
- 零基础学python大概要多久-零基础学python大概要多久
- No subdirectories found for mandatory directory location ‘file: /config/*/‘
- PWA(Progressive Web App)入门系列:(一)PWA简介
- 用cobar搭建分布式数据库 .
- 《羊了个羊》创始人被母校制成展牌...
- MATLAB2013实现图像处理GUI界面设计
- PDF被密码保护怎么解除?一篇文章教会你
- 跨境电商erp系统是什么?
- 赠书:HTML5 Canvas 2d 编程必读的两本经典
- 七、后台入口及添加影院实现《仿淘票票系统前后端完全制作(除支付外)》