图有5种存储结构:邻接矩阵、邻接多重表、邻接表、边集数组、十字链表。
一、邻接矩阵
对于无权无向图:若顶点 i 与顶点 j 间有边,则 V[i][j] = V[j][i] = 1,若无边,则为0。V[i][i] 必为0。此时邻接矩阵必为对称矩阵。
对于无权有向图:若顶点 i 与顶点 j 间有边,则 V[i][j] = 1,若无边,则为0。V[i][i] 必为0。
对于有权有向图:若顶点 i 与顶点 j 间有边,则 V[i][j] = 权,若无边,则为无穷。V[i][i] 必为0。
邻接矩阵存在一个问题:当顶点多而边很少时,极大地浪费了空间。
//建立无向网图的邻接矩阵表示
typedef char VertexType; //顶点类型
typedef int EdgeType; //边的权值类型
#define MAXVEX 100 //最大顶点数
#define INFINITY 65535 //用65535来代表无穷
typedef struct
{
VertexType vexs[MAXVEX]; //顶点表
EdgeType arc[MAXVEX][MAXVEX]; //邻接矩阵
int numVertexes, numEdges; //图中当前的定点数和边数
}MGraph;
void CreateMGraph(MGraph* G)
{
int i, j, k, w;
printf("输入顶点数和边数:");
scanf("%d,%d", G->numVertexes, G->numEdges);
for (i = 0; i < G->numVertexes; i++) //读入顶点信息,建立顶点表
{
scanf(&G->vexs[i]);
}
for (i = 0; i < G->numVertexes; i++) //初始化
for (j = 0; j < G->numEdges; j++)
G->arc[i][j] = INFINITY;
for (k = 0; k < G->numEdges; k++) //输入numEdges条边,建立邻接矩阵
{
printf("输入边(vi,vj)的下标 i 、下标 j 和权 w :");
scanf("%d,%d,%d", &i, &j, &w);
G->arc[i][j] = w;
G->arc[j][i] = w;
}
}
二、邻接表
用链表解决矩阵有太多无用空间的问题。
- 建立一个数组表示每一个顶点元素,每一个元素包含两部分,一是顶点数据,而是指向其边表头部的指针。
- 每个顶点的所有邻接表构成一个链表
//建立无向网图的邻接矩阵表示
typedef char VertexType; //顶点类型
typedef int EdgeType; //边的权值类型
#define MAXVEX 100 //最大顶点数
typedef struct EdgeNode //边表结点
{
int adjvex; //邻接点域,存储该点对应的下标
EdgeType wight; //存储权值,非网图可以不需要
struct EdgeNode* next; //链域,指向下一个邻接点
}EdgeNode;
typedef struct VertexNode //顶点表结点
{
VertexType data; //顶点域,存储顶点信息
EdgeNode* firstedge; //边表头指针
}VertexNode, AdjList[MAXVEX];
typedef struct
{
AdjList adjList;
int numVertexes, numEdges; //图中当前顶点数和边数
}GraphAdjList;
void CreatGraph(GraphAdjList* G)
{
int i, j, k;
EdgeNode* e;
printf("输入顶点数和边数:");
scanf("%d,%d", &G->numVertexes, &G->numEdges);
for (i = 0; i < G->numVertexes; i++) //读入顶点信息,建立顶点表
{
scanf(&G->adjList[i]->data); //输入顶点信息
G->adjList->firstedge = NULL; //将边表置位空表
}
for (k = 0; k < G->numEdges; k++) //建立边表
{
printf("输入边(vi,vj)变上的顶点序号:");
scanf("%d,%d", &i, &j);
e = (EdgeNode*)malloc(sizeof(EdgeNode)); //向内存申请空间形成边表结点
e->adjvex = j; //邻接序号为j
e->next = G->adjList[i].firstedge; //将e指针至于 vi 的边表的第一个
G->adjList[i].firstedge = e; //
e->adjvex = i; //无向图是对称矩阵
e->next = G->adjList[j].firstedge;
G->adjList[j].firstedge = e;
}
}