对于一个图(graph)G=(V,E)由顶点集V(vertex)和边集E(edges)组成。每一条边就是一个点对(u,w),其中u、w属于V。
邻接矩阵本质上就是一个二维数组,例如对于每条边(u,w),可以表示为A[u][w]=1(边没有权值),否则A[u][w]=0(这条边不存在)。如果边有权值,可以令A[u][w]=权值。
邻接表使用一个表来存放所有邻接的顶点。
邻接表:由上图可知,邻接表节点由头结点和表节点组成
(1)头表结点结构
┌────┬─────┐
│data │ firstedge │
└────┴─────┘
顶点vi邻接表的头结点包含两个域:
① 顶点域data
存放顶点vi的信息
② 指针域firstedge
vi的邻接表的头指针。
(2)边表结点结构
┌────┬───┐
│adjvex │next │
└────┴───┘
邻接表中每个表结点均有两个域:
① 邻接点域adjvex
存放与vi相邻接的顶点vj的序号j。
② 链域next
将邻接表的所有表结点链在一起。
注意:
--- 若要表示边上的信息(如权值),则在表结点中还应增加一个数据域。
---上述图用邻接表表示为:
A B C D
A 0 1 1 1
B 1 0 0 1
C 1 0 0 0
D 1 1 0 0
在C语言中,如果我们想表示标准C语言不存在的数据类型,一般使用结构体来实现。把已有的数据类型组合成我们想要的数据类型。表示一张图,需要的参数有:图的顶点数,图的边数,一个二维数组,因此可以定义一个结构体包含三种类型的数据
#define ROW 100
#define COL 100
typedef struct AdjMatrix
{
int matrix[ROW][COL];
int NumVertex; //图的顶点数
int Numedges; //图的边数
}MGraph;
//使用指针进行构建,自己管理内存
typedef struct AdjMatrix_P
{
int *matrix;
int NumVertex; //图的顶点个数
int Numedges; //图的边数
}MPGraph;
使用第一个数据类型构建一张图:
void CreateGraph_AM(MGraph *G)
{
int i=0,j=0;
int s,t,w;
cout<<"请输入顶点数和边数:";
cin>>G->NumVertex>>G->Numedges;
for(i=0;iNumVertex;i++)
for(j=0;jNumVertex;j++)
{
G->matrix[i][j]=0;
}
for(i=0;iNumedges;i++)
{
cout<<"请输入第"<>s>>t>>w;
G->matrix[s][t]=w;
}
}
void print_AM(MGraph *G)
{
int i=0,j=0;
for(i=0;iNumVertex;i++)
{
for(j=0;jNumVertex;j++)
{
cout<matrix[i][j]<
使用第二种数据类型构建一张图:
void CreateGraph_AMP(MPGraph *G)
{
int i=0,j=0;
int s,t,w;
cout<<"请输入顶点数和边数:";
cin>>G->NumVertex>>G->Numedges;
G->matrix=(int *)malloc(G->NumVertex*G->NumVertex*sizeof(int));
if(G->matrix==NULL)
{
cout<<"内存分配失败";
return;
}
for(i=0;iNumVertex;i++) //初始化
for(j=0;jNumVertex;j++)
{
*(G->matrix+i*G->NumVertex+j)=0;
}
for(i=0;iNumedges;i++)
{
cout<<"请输入第"<>s>>t>>w;
*(G->matrix+s*G->NumVertex+t)=w;
}
}
void print_AMP(MPGraph *G)
{
int i=0,j=0;
for(i=0;iNumVertex;i++)
{
for(j=0;jNumVertex;j++)
{
cout<matrix+i*G->NumVertex+j)<
邻接表由表头顶点和边表节点组成,因此要先定义头顶点和边表节点的数据结构。
typedef char VertexType;
//边表节点
typedef struct _EdgeNode
{
int adjvex; //边表顶点号,用于存放于头表顶点邻接的顶点Vj的序号j
int weight; //权值
struct _EdgeNode * next; //指向下一个边表节点
}EdgeNode;
typedef struct _VNode //头顶点信息
{
VertexType data; //存放顶点的信息。。。
EdgeNode *firstEdge;
}VNode;
#define MAXVERTEXNUM 100
typedef struct AdjList
{
VNode adjList[MAXVERTEXNUM];
int NumVertex;
int Numedges;
}LGraph;
//用指针来实现
typedef struct AdjList_P
{
VNode *adjList; //需要分配内存
int NumVertex;
int Numedges;
}LPGraph;
void CreateGraph_AL(LGraph *G)
{
int i=0;
int s,t,w;
VertexType data;
cout<<"请输入顶点数和边数:";
cin>>G->NumVertex>>G->Numedges;
//初始化表头
for(i=0;iNumVertex;i++)
{
cout<<"请输入第"<>data;
G->adjList[i].data=i;
G->adjList[i].firstEdge=NULL;
}
for(i=0;iNumedges;i++)
{
cout<<"请输入第"<>s>>t>>w;
EdgeNode *p=(EdgeNode*)malloc(sizeof(EdgeNode)); //定义一个边表节点指针,并为其分配内存
if(p==NULL)
{
cout<<"内存分配失败";
return;
}
//修改指针,每次在表头节点后面插入新的节点,其它节点后移
p->next=G->adjList[s].firstEdge;
G->adjList[s].firstEdge=p;
p->adjvex=t;
p->weight=w;
}
}
void print_AL(LGraph *G)
{
int i=0;
for(i=0;iNumVertex;i++)
{
if(G->adjList[i].firstEdge==NULL)
{
cout<<"第"<adjList[i].data<<" 邻接表:->NULL";
cout<adjList[i].data<<" 邻接表:";
EdgeNode *q=G->adjList[i].firstEdge;
while(q!=NULL)
{
cout<<"->"<adjList[q->adjvex].data;
q=q->next;
}
cout<
使用第二种数据类型构建一张图:需要为头顶点指针分配内存
void CreateGraph_ALP(LPGraph *G)
{
int i=0;
int s,t,w;
VertexType data;
cout<<"请输入顶点数和边数:";
cin>>G->NumVertex>>G->Numedges;
G->adjList=(VNode *)malloc(G->NumVertex*sizeof(VNode));
if(G->adjList==NULL)
{
printf("内存分配失败");
return;
}
//1.初始化
for(i=0;iNumVertex;i++)
{
cout<<"请输入第"<>data;
G->adjList[i].data=data;
G->adjList[i].firstEdge=NULL;
}
//2.记录边与权值
for(i=0;iNumedges;i++)
{
cout<<"请输入第"<>s>>t>>w;
EdgeNode *p=(EdgeNode*)malloc(sizeof(EdgeNode)); //定义一个边表节点指针,并为其分配内存
if(p==NULL)
{
cout<<"内存分配失败";
return;
}
//修改指针,每次在表头节点后面插入新的节点,其它节点后移
p->next=G->adjList[s].firstEdge;
G->adjList[s].firstEdge=p;
p->adjvex=t;
p->weight=w;
}
}
void print_ALP(LPGraph *G)
{
int i=0;
for(i=0;iNumVertex;i++)
{
if(G->adjList[i].firstEdge==NULL)
{
cout<<"第"<adjList[i].data<<" 邻接表:->NULL";
cout<adjList[i].data<<" 邻接表:";
EdgeNode *q=G->adjList[i].firstEdge;
while(q!=NULL)
{
cout<<"->"<adjList[q->adjvex].data;
q=q->next;
}
cout<
(1)找顶点的所有邻接顶点
邻接矩阵:可以判断对应顶点序号的一维数组的值,例如:A[1][...]=? 若=0,邻接;=1邻接
邻接表:扫描对应的邻接表
(2)内存
邻接矩阵占用的内存:O(V平方)
邻接表:O(V+E)
若图是稠密的,选择邻接矩阵是合适的;若图是稀疏的,选择邻接表是合适的;