有向图和无向图
邻接矩阵、邻接表的定义及其基本算法
#include <stdio.h>
#include<string.h>
#include<malloc.h>
/*--------------
实现图的邻接矩阵和邻接表存储
*/
#define INF 32767 //定义无穷大
#define MAXV 100 //最大顶点个数
typedef char InfoType;
//----------------------定义邻接矩阵类型
/*=============
有两个数组:顶点数组和边数组
顶点数组:存储图中所有顶点信息
边数组:存储顶点与顶点间的路径
无向图的边数组是对称矩阵
==================*/
//顶点类型
typedef struct{
int no; //顶点编号
InfoType info; //顶点其他信息
}VertexType;
//完整的图邻接矩阵类型
typedef struct{
int edges[MAXV][MAXV]; //领接矩阵数组【边数组】
int n,e; //顶点数、边数【顶点数组】
VertexType vexs[MAXV]; //存放顶点信息
}MatGraph;
//---------------------定义邻接表类型
/*=============
图中顶点用一维数组或单链表存储【一般用数组存储】
邻接列表的第i个列表是所有直接连接到第i个顶点的所有顶点的列表。
无向图存储所有与顶点vi直接相连的顶点 ,所以会有冗余,两顶点的路径回重复存储两遍
有向图存储的是从vi顶点出发能直接到达的顶点
==================*/
//边结点类型
typedef struct ANode{
int adjvex; //该边的邻接点编号
struct ANode *nextarc; //指向下一条边的指针
int weight; //该边的相关信息,如权值
}ArcNode; //边结点类型
//邻接表头结点类型
typedef struct Vnode{
InfoType info; //顶点其他信息
int count; //存放顶点入度,仅仅用于拓扑排序
ArcNode *firstarc; //指向第一条边
}VNode;
//完整的图邻接表类型
typedef struct{
VNode adjlist[MAXV]; //邻接表头结点数组
int n,e; //图中顶点数n和边数e
}AdjGraph;
//邻接矩阵的基本运算算法-------------
//创建图的邻接矩阵
void CreateMat(MatGraph &g,int A[MAXV][MAXV],int n,int e){
//A:边数组; n:顶点数;e:边数
int i,j;
g.n=n;g.e=e; //存储图的顶点数,边数
for(i=0;i<g.n;i++) //行
for(j=0;j<g.n;j++) //列
g.edges[i][j] = A[i][j]; //赋值
}
//输出邻接矩阵g
void DispMat(MatGraph g){
int i,j;
for(i=0;i<g.n;i++){
for(j=0;j<g.n;j++)
if(g.edges[i][j]!=INF)
printf("%4d",g.edges[i][j]);
//"%4d":起到固定位数的输出格式。如果该整数小于四位,前面会输出空格
// 保证四位输出格式,如果该整数大于四位,按正常输出
else
printf("%4s","∞");
printf("\n");
}
}
//邻接表的基本运算算法----------------------
//创建图的邻接表
void CreateAdj(AdjGraph *&G,int A[MAXV][MAXV],int n,int e){
int i,j;
ArcNode *p;
G=(AdjGraph *)malloc(sizeof(AdjGraph));
//给邻接表中所有头结点的指针域初始值
for(i=0;i<n;i++){
G->adjlist[i].firstarc = NULL;
//当结构体是一个指针时,要引用结构体的成员就用-> 而如果不是指针就用.
//adjlist[]邻接表头结点数组;firstarc指向该顶点的第一条边
}
//检查邻接矩阵中的每个元素
for(i=0;i<n;i++)
for(j=n-1;j>=0;j--)
if(A[i][j]!=0 && A[i][j]!=INF){ //存在一条边
p=(ArcNode *)malloc(sizeof(ArcNode)); //创建边结点p
p->adjvex = j; //存储邻接点编号
p->weight = A[i][j]; // 该边的相关信息,如权值
p->nextarc = G->adjlist[i].firstarc; //指向下一条边
G->adjlist[i].firstarc = p;
/*---------------
用头插法将p结点插入第i个邻接列表中 ,所以遍历列时是从后往前遍历
--------------------*/
}
G->n=n;G->e=n;
}
//输出邻接表G
void DispAdj(AdjGraph *G){
ArcNode *p;
for(int i=0;i<G->n;i++){
p=G->adjlist[i].firstarc;
printf("%3d:",i); //输出第i个表头结点
while(p!=NULL){
printf("%3d[%d]->",p->adjvex,p->weight);
p=p->nextarc;
}
printf("^\n");
}
}
//销毁图的邻接表
void DestroyAdj(AdjGraph *&G){
ArcNode *pre,*p;
int i;
for(i=0;i<G->n;i++){ //扫描所有的单链表
pre=G->adjlist[i].firstarc; //p指向第i个单链表的首结点
if(pre!=NULL){
p=pre->nextarc;
while(p!=NULL){ //释放第i个单链表的所有边结点
free(pre);
pre=p;
p=p->nextarc;
}
free(pre);
}
}
free(G); //释放头结点数组
}
main函数
#include"graph.cpp" //包含图的存储结构及基本运算算法
int main(){
MatGraph g;
AdjGraph *G;
int A[MAXV][MAXV] = {
{0,5,INF,7,INF,INF},
{INF,0,4,INF,INF,INF},
{8,INF,0,INF,INF,9},
{INF,INF,5,0,INF,6},
{INF,INF,INF,5,0,INF},
{3,INF,INF,INF,1,0}
};
int n=6,e=10;
CreateMat(g,A,n,e);
printf("图G的邻接矩阵:\n");
DispMat(g);
CreateAdj(G,A,n,e);
printf("图G的邻接表:\n");
DispAdj(G);
printf("销毁图G的邻接表\n");
DestroyAdj(G);
return 1;
}
运行结果