图(graph)是由非空顶点集合以及描述顶点(vertex)之间关系的弧(edge)构成的一种数据结构。可以定义为G={v,e}的二元组
今天介绍图的两种实现方式,分别是邻接矩阵和邻接表
1.邻接矩阵实现图
(1)邻接矩阵简介
邻接矩阵是由顶点之间的相邻关系建立的矩阵
在弧的弧头和弧尾的对应数组中插入对应弧的权值元素,后面实现的表为有向表,无向表的实现时将矩阵设计为对称矩阵。
后文实现的图(本文用-1代表两点之间不存在关系)
(2)构建邻接矩阵的结构体
typedef struct Graph{
int ver; //定义顶点
int** edge; //定义边之间关系
}Graph;
矩阵就是一个二维数组来实现顶点关系的存储。
(3)创建矩阵
void Graph_creat(Graph* g,int ver)//创建矩阵
{
g->ver=ver;
g->edge=(int**)malloc(sizeof(int*)*ver);//初始化矩阵
int i,j;
for(i=0;i<ver;++i)
{
g->edge[i]=(int*)malloc(sizeof(int)*ver);
for(j=0;j<ver;++j)
{
g->edge[i][j]=inf;//将矩阵填入inf,代表现在顶点间不存在关系
}
}
}
初始化元素包括,将顶点数填入以及将矩阵上的元素填入为-1 两步将矩阵的基本架构建立
(4)矩阵的销毁
void Graph_distory(Graph* g)//销毁
{
int i,j;
for(i=0;i<g->ver;++i)
{
free(g->edge[i]);//遍历矩阵销毁节点
}
free(g->edge);
g->edge=NULL;//最后将表置空
}
遍历完之后还要对矩阵这个结进行销毁,并将矩阵置空。
(5)矩阵元素的插入
void Graph_insert(Graph* g,int i,int j,int weight)
{
g->edge[i][j]=weight;
}
元素的插入就是将弧的权值插入矩阵中
(6)矩阵的输出
void Graph_print(Graph* g)
{
int i,j;
for(i=0;i<g->ver;++i)
{
for(j=0;j<g->ver;++j)
{
printf("%d\t",g->edge[i][j]);//遍历输出元素
}
printf("\n");
}
}
简单遍历全矩阵来输出元素,并用tab缩进来保持输出元素的整齐。
(7)完整矩阵代码实现
#include<stdio.h>
#include<stdlib.h>
#define inf -1
typedef struct Graph{
int ver;
int** edge;
}Graph;
void Graph_creat(Graph* g,int ver)
{
g->ver=ver;
g->edge=(int**)malloc(sizeof(int*)*ver);
int i,j;
for(i=0;i<ver;++i)
{
g->edge[i]=(int*)malloc(sizeof(int)*ver);
for(j=0;j<ver;++j)
{
g->edge[i][j]=inf;
}
}
}
void Graph_distory(Graph* g)
{
int i,j;
for(i=0;i<g->ver;++i)
{
free(g->edge[i]);
}
free(g->edge);
g->edge=NULL;
}
void Graph_insert(Graph* g,int i,int j,int weight)
{
g->edge[i][j]=weight;
}
void Graph_print(Graph* g)
{
int i,j;
for(i=0;i<g->ver;++i)
{
for(j=0;j<g->ver;++j)
{
printf("%d\t",g->edge[i][j]);
}
printf("\n");
}
}
int main()
{
Graph g;
Graph_creat(&g,3);//定义节点数为3
Graph_insert(&g,0,1,7);//插入元素0-》1权值为7
Graph_insert(&g,1,2,3);//插入元素1-》2权值为3
Graph_insert(&g,2,0,2);//插入元素2-》0权值为2
Graph_print(&g);//输出表
Graph_distory(&g);//销毁表
return 0;
}
2.邻接表实现图
(1)邻接表的简介
邻接表(adjacency list)是用顺序结构和链表结构结合的结构实现对元素弧之间关系的存储,相较于邻接矩阵而言在存储稀疏图是更有利于节约存储空间,不会造成大量空间的浪费。
上图为后面要实现的图结构
(2)邻接表的结构
邻接表的三个结构体(1)节点结构由顶点元素域(vertex)和指向第一个元素节点的指针(first)构成(2)边表结构由顶点下标值(vertex),权值(weight)和指向下一个弧节点的指针(next)(3)链表结构由节点数(verties)和指向顶点的指针(node)
typedef struct edgenode{
int vertex;
int weight;
struct edgenode* next;
}edgenode;//顶点
typedef struct vernode{
char vertex;
edgenode* first;
}vernode;
typedef struct{
int verties;
vernode* node;
}graph;
(3)邻接表的初始化
将元素的值输入对应的结构中,再将元素指向的第一个顶点的指针置空
void graphcreate(graph* g,int verties)//初始化
{
g->verties=verties;//将顶点数赋予表结构的顶点值
g->node=(vernode*)malloc(sizeof(vernode)*verties);//初始化表结构
int i;
for(i=0;i<g->verties;++i)
{
printf("请输入第%d个元素\n",i+1);
g->node[i].vertex=getchar();//遍历输入元素的内容值
getchar();
g->node[i].first=NULL; //将每一个顶点指向的第一个顶点的指针置为空
}
}
(4)邻接表的删除
删除操作域链表删除操作一致,构建一个新节点来遍历全表和一个节点进行删除操作
void graphdistory(graph* g)//删除
{
int i;
for(i=0;i<g->verties;++i)
{
edgenode* cur=g->node[i].first;//增加一个节点来容纳邻接表第一个节点
while(cur)
{
edgenode* temp;//存放cur节点来进行删除操作
temp=cur;
cur=cur->next;
free(temp);
}
}
free(g->node);//将邻接表删除
g->node=NULL;//将表置空
}
(5)邻接表的插入 (头插法)
插入需要的元素有顶点对应的下标(u),弧尾元素下标值(v),以及弧上的权值(w)
void graphinsert(graph* g ,int u,int v,int w)
{
edgenode* newnode =(edgenode*)malloc(sizeof(edgenode));
newnode->vertex=v;
newnode->weight=w;
newnode->next=g->node[u].first;//将下一个节点赋值给u节点的首节点
g->node[u].first=newnode;//头插法插入newnode节点
}
(6)领接表的输出
就是将邻接表遍历输出,仅需注意输出的格式
void graphdisplay(graph* g)
{
int i;
for(i=0;i<g->verties;++i)//遍历输出元素
{
edgenode* cur=g->node[i].first;
printf("%c->",g->node[i].vertex);//先输出元素的内容
while(cur)
{
printf("%d(%d)->",cur->vertex,cur->weight);
cur=cur->next;
}
printf("NULL\n");//用NULL代表最后一个指针为空
}
}
(7)完整实现代码
#include<stdio.h>
#include<stdlib.h>
typedef struct edgenode{
int vertex;
int weight;
struct edgenode* next;
}edgenode;//顶点
typedef struct vernode{
char vertex;
edgenode* first;
}vernode;
typedef struct{
int verties;
vernode* node;
}graph;
void graphcreate(graph* g,int verties)
{
g->verties=verties;//将顶点赋予权值数量
g->node=(vernode*)malloc(sizeof(vernode)*verties);
int i;
for(i=0;i<g->verties;++i)
{
printf("请输入第%d个元素\n",i+1);
g->node[i].vertex=getchar();
getchar();
g->node[i].first=NULL;
}
}
void graphdistory(graph* g)
{
int i;
for(i=0;i<g->verties;++i)
{
edgenode* cur=g->node[i].first;
while(cur)
{
edgenode* temp;
temp=cur;
cur=cur->next;
free(temp);
}
}
free(g->node);
g->node=NULL;
}
void graphinsert(graph* g ,int u,int v,int w)
{
edgenode* newnode =(edgenode*)malloc(sizeof(edgenode));
newnode->vertex=v;
newnode->weight=w;
newnode->next=g->node[u].first;
g->node[u].first=newnode;
}
void graphdisplay(graph* g)
{
int i;
for(i=0;i<g->verties;++i)
{
edgenode* cur=g->node[i].first;
printf("%c->",g->node[i].vertex);
while(cur)
{
printf("%d(%d)->",cur->vertex,cur->weight);
cur=cur->next;
}
printf("NULL\n");
}
}
int main()
{
graph g;
graphcreate(&g,5);//初始化节点为5个,元素内容分别为A,B,C,D,E
graphinsert(&g,0,1,4);//下标为0的元素指向下标为1的元素,权值为4
graphinsert(&g,0,2,2);//下标为0的元素指向下标为2的元素,权值为3
graphinsert(&g,1,2,3);//下标为1的元素指向下标为2的元素,权值为3
graphinsert(&g,2,3,4);//下标为2的元素指向下标为3的元素,权值为4
graphinsert(&g,3,4,2);//下标为3的元素指向下标为4的元素,权值为2
graphdisplay(&g);//输出表
graphdistory(&g);//将表销毁
return 0;
}
实现后的结果如图
如有错漏敬请指正