1.图的定义
图是一种相对较为复杂的数据结构,由结点及各结点之间的相互关系组成。图中结点之间的关系可以是任意的,也就是说图中任何两个结点之间都可能是有关系的。图中的各个结点称为顶点(vertex)。图分为有向图和无向图。图一中左边是有向图,右边是无向图。
图一
2.图的存储结构
2.1数组表示法
数组表示法又称为邻接矩阵表示法,是用两个数组分别存储顶点信息和顶点之间的关系即边的信息。
#define VERTEXNUM 100 //存储顶点数目
typedef int VertexType;
typedef int EdgeType;
typedef struct
{
VertexType vertexs[VERTEXNUM]; //顶点表
EdgeType edges[VERTEXNUM][VERTEXNUM]; //邻接矩阵存储顶点间关系
int vernum, edgenum; //图中当前的顶点和边数
}Graph;
邻接矩阵表示中建立邻接矩阵及输出程序如下:
#include <cstdio>
#include <cstdlib>
#define VERTEXNUM 100 //存储顶点数目
typedef int VertexType;
typedef int EdgeType;
typedef struct
{
VertexType vertexs[VERTEXNUM]; //顶点表
EdgeType edges[VERTEXNUM][VERTEXNUM]; //邻接矩阵存储顶点间关系
int vernum, edgenum; //图中当前的顶点和边数
}Graph;
void MakeGraph(Graph *&graph)
{
int v1, v2;
int i, j, k;
printf("请输入图的顶点数n和边数e:\n");
scanf("%d%d", &graph->vernum, &graph->edgenum);
printf("顶点编号设置为1~n.\n");
for(i = 0; i < graph->vernum; i++)
{
graph->vertexs[i] = i + 1;
}
for(i = 0; i < graph->vernum; i++) //边信息初始化
{
for(j = 0; j < graph->vernum; j++)
{
graph->edges[i][j] = 0;
}
}
printf("请输入每条边对应的两个顶点的序号(格式为i,j):\n");
for(k = 0; k < graph->edgenum; k++)
{
scanf("%d,%d", &v1, &v2);
graph->edges[v1 - 1][v2 - 1] = 1;
}
}
int main()
{
Graph *graph = (Graph *)malloc(sizeof(Graph));
MakeGraph(graph);
//输出邻接矩阵
for(int i = 0; i < graph->vernum; i++)
{
for(int j = 0; j < graph->vernum; j++)
{
printf("%d ", graph->edges[i][j]);
}
printf("\n");
}
return 0;
}
2.2邻接表表示法
邻接表中,对图中每个顶点建立一个单链表,单链表i中的结点表示依附于顶点vi的边。将这些单个的单链表连接组成的链式存储结构就是图的邻接表(Adjacency List)。结构如下:
#define VERTEXNUM 100 //顶点个数
typedef int VertexType;
typedef int EdgeType;
typedef struct node
{
int adjvex; //顶点位置
struct node *next; //指向下一条边的指针
}EdgeNode;
typedef struct vnode
{
VertexType vertex; //顶点信息
EdgeNode *firstedge; //指向第一条依附该顶点的边的指针
}AdjList[VERTEXNUM];
typedef struct
{
AdjList vertexs; //邻接表
int vernum, edgenum; //图中当前的顶点和边数
}Graph;
建立邻接表及其输出程序如下:
#define VERTEXNUM 100 //顶点个数
typedef int VertexType;
typedef int EdgeType;
typedef struct node
{
int adjvex; //顶点位置
struct node *next; //指向下一条边的指针
}EdgeNode;
typedef struct vnode
{
VertexType vertex; //顶点信息
EdgeNode *firstedge; //指向第一条依附该顶点的边的指针
}AdjList[VERTEXNUM];
typedef struct
{
AdjList vertexs; //邻接表
int vernum, edgenum; //图中当前的顶点和边数
}Graph;
void MakeGraph(Graph *graph)
{
int i, j, k;
printf("请输入图的顶点数n和边数e:\n");
scanf("%d%d", &graph->vernum, &graph->edgenum);
printf("顶点编号设置为1~n.\n");
for(i = 0; i < graph->vernum; i++)
{
graph->vertexs[i].vertex = i + 1; //顶点编号为1~n
graph->vertexs[i].firstedge = NULL; //初始第一条边为空
}
printf("请输入每条边对应的两个顶点的序号(格式为i,j):\n");
EdgeNode *p;
for(k = 0; k < graph->edgenum; k++)
{
scanf("%d,%d", &i, &j); //读入边<vi,vj>的序号
p = (node *)malloc(sizeof(node)); //生成新的结点
p->adjvex = j;
p->next = graph->vertexs[i - 1].firstedge;
graph->vertexs[i - 1].firstedge = p;
}
}
int main()
{
Graph *graph = (Graph *)malloc(sizeof(Graph));
MakeGraph(graph);
EdgeNode *p;
//输出邻接表
for(int i = 0; i < graph->vernum; i++)
{
p = graph->vertexs[i].firstedge;
while(p != NULL)
{
printf("%d ", p->adjvex);
p = p->next;
}
printf("\n");
}
return 0;
}
2.3十字链表
十字链表可以看成是将有向图的邻接表和逆邻接表结合得到的一种链表。在十字链表中,因为容易找到以某顶点为尾的边,也容易找到以其为头的边,因而比较容易求得顶点的出度和入度。