目录
- 5. 图
- 5.1 图的抽象数据结构
- 5.2 图的表示方法
- 5.3 图的定义与术语总结
- 5.4 邻接矩阵
- 5.4.1 邻接矩阵存储的图深度优先遍历
- 5.4.2 邻接矩阵存储的图广度优先遍历
- 5.5 临接表表示法
- 5.5.1 临接表表示的图深度优先遍历
- 5.5.2 临接表表示的图广度优先遍历
5. 图
5.1 图的抽象数据结构
ADT Graph
Data
顶点的有穷非空集合和边的集合
Operation
CreateGraph(*G, V, VR) 按照顶点集和边弧集VR的定义构造图G
DestoryGraph 图G存在则销毁
LocateVex(G, u) 若存在顶点u,则返回图中的位置
GetVex(G, u),返回顶点u的值
InsertVex(*G, v) 在图中新增顶点v
DeleteVex(*G, v) 删除图中顶点v和相关弧
InsertArc(*G, v, w) 在图中增添弧<v, w>
DFSTraverse(G) 深度优先遍历,在遍历过程中对每个顶点调用
HFSTraverse(G) 对图中进行广度优先遍历,在遍历过程中对每个顶点调用
endADT
5.2 图的表示方法
- 图的表示方法中,不允许出现图的节点为空的情况!
- 无向图的表示方法G = (V1, {E1}) V1 = {A,B,C,D} , E1 = {(A,B), (B,C), (C,D),
(D, A)} 无向图使用小括号()
- 有向图的表示方法G = (V2, {E2}) V1= {A,B,C,D}, E2 = {, , ,
} 有向图使用<>,同时第一个元素表示弧尾,第二个元素表示弧首
5.3 图的定义与术语总结
- 图分为无向图和有向图,无向图有顶点和边构成,有向图由顶点和弧构成,弧有弧尾和弧头之分
- 任意两个顶点之间都存在边叫做完全图,有向的叫有向完全图,若无重复的边或顶点到自身,叫做简单图
- 图中顶点之间有邻接点、依附的概念,无向图顶点的边数叫做度,有向图顶点分为入度和出度
- 简单路径:路径最终回到起点且不重复,若任意两顶点都是连通的,是连通图,有向则称为强连通图
- 生成树:无向图中连通N个顶点的n-1条边叫做生成树
5.4 邻接矩阵
#include
#include
typedef char VertexType;
typedef int EdgeType;
#define MAXVEX 100
#define INFINITY 65535
typedef struct {
VertexType vexs[MAXVEX];
EdgeType arc[MAXVEX][MAXVEX];
int numVertexes, numEdges;
} MGraph;
void CreateGraph(MGraph *G)
{
int i, j, k, w;
printf("输入顶点数和边数:\n");
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->numVertexes; j++) {
G->arc[i][j] = INFINITY;
}
}
for (k = 0; k < G->numEdges; k++) {
printf("输入边的上下标\n");
scanf("%d %d %d", &i, &j, &w);
G->arc[i][j] = w;
G->arc[j][i] = G->arc[i][j];
}
}
5.4.1 邻接矩阵存储的图深度优先遍历
typedef int Boolean;
Boolean visited[MAXVEX];
void DFS(MGraph G, int i)
{
int j;
visited[i] = true;
printf("%d", G.vexs[i]);
for (j = 0; j < G.numVertexes; j++) {
if (G.arc[i][j] == 1 && !visited[j]) {
DFS(G, j);
}
}
}
void DFSTraverse(MGraph G)
{
int i, j;
memset(visited, 0, sizeof(visited[0])*MAXVEX);
for (i = 0; i < G.numVertexes; i++) {
if (!visited[i]) {
DFS(G, i);
}
}
}
void DFS(MGraph G, int i)
{
int j;
stack s;
visited[i] = 1;
printf("%c", G.vexs[i]);
Push(&s, i);
while (!StackEmpty(s)) {
i = s.top()
for (j = 0; j < G.numVertexes; j++) {
if (G.arc[i][j] == 1 && !visited[j]) {
visited[j] = 1;
printf("%c", G.vexs[j]);
Push(&s, j);
break;
}
}
if (j == G.numVertexes) {
Pop(&s);
}
}
}
void DFSTraverse(MGraph G)
{
int i;
for (i = 0; i < G.numVertexes; i++) {
visited[i] = 0;
}
for (i = 0; i < G.numVertexes; i++) {
if (!visited[i]) {
DFS(G, i);
}
}
}
5.4.2 邻接矩阵存储的图广度优先遍历
void BFSTraverse(MGraph G)
{
int i, j;
Queue Q;
for (i = 0; i < G.numVertexes; i++) {
visited[i] = FALSE;
}
InitQueue(&Q);
for (i = 0; i < G.numVertexes; i++) {
if (!visited[i]) {
visited[i] = true;
printf("%c", G.vexs[i]);
EnQueue(&G, i);
while (!QueueEmpty(&G)) {
DEQueue(&G, &i);
for (j = 0; j < G.numVertexes; j++) {
if (!visited[j] && G.arc[i][j] == 1) {
visited[j] = true;
printf("%c", G.vexs[j]);
EnQueue(&G, j);
}
}
}
}
}
}
5.5 临接表表示法
#include
#include
#define MAXVEX 100
typedef char VertexType;
typedef int EdgeType;
typedef struct EdgeNode {
int adjvex;
EdgeType weight;
struct EdgeNode *next;
} EdgeNode;
typedef struct VertexNode {
VertexType data;
struct EdgeNode *firstEdge;
} VertexNode, AdjList[MAXVEX];
typedef struct {
AdjList adjList;
int numVertexes, numEdges;
} GraphAdjList;
void CreateGraph(GraphAdjList *G)
{
int i, j, k;
EdgeNode *e;
printf("输入定点数和边数:\n");
scanf("%d %d", &G->numVertexes, &G->numEdges);
for (i = 0; i < G->numVertexes; i++) {
scanf(&G->adjList[i].data);
G->adjList[i].firstEdge = NULL;
}
for (k = 0; k < G->numEdges; k++) {
printf("输入边上的顶点号\n");
scanf("%d %d", &i, &j);
e = (EdgeNode *)malloc(sizeof(EdgeNode));
e->adjvex = j;
e->next = G->adjList[i].firstEdge;
G->adjList[i].firstEdge = e;
e = (EdgeNode *)malloc(sizeof(EdgeNode));
e->adjvex = i;
e->next = G->adjList[j].firstEdge;;
G->adjList[j].firstEdge = e;
}
}
5.5.1 临接表表示的图深度优先遍历
typedef int Boolean;
Boolean visited[MAXVEX];
void DFS(GraphAdjList *GL, int i)
{
EdgeNode *p;
visited[i] = true;
printf("%c", GL->adjList[i].data);
p = GL->adjList[i].firstEdge;
while (p) {
if (!visited[p->adjvex]) {
DFS(GL, p->adjvex);
}
p = p->next
}
}
void DFSTraverse(GraphAdjList *GL)
{
int i;
for (i = 0; i < GL->numVertexes; i++) {
visited[i] = FALSE;
}
for (i = 0; i < GL->numVertexes; i++) {
if (!visited[i]) {
DFS(GL, i);
}
}
}
void DFS(GraphAdjList *GL, int i)
{
stack s;
EdgeNode *p;
printf("%c", GL->adjList[i].data);
visited[i] = 1;
Push(&s, i)
while (!StackEmpty(s)) {
p = GL->adjList[s.top()].firstEdge;
while (p) {
if (!visited[p->adjvex]) {
visited[p->adjvex] = 1;
printf("%c", GL->adjList[p->adjvex].data);
Push(&s, p->adjvex);
p = GL->adjList[p->adjvex].firstEdge;
} else {
p = p->next;
}
}
if (p == NULL) {
Pop(&s);
}
}
}
void DFSTraverse(GraphAdjList *GL)
{
int i;
for (i = 0; i < GL->numVertexes; i++) {
visited[i] = 0;
}
for (i = 0; i < GL->numVertexes; i++) {
if (!visited[i]) {
DFS(GL, i);
}
}
}
5.5.2 临接表表示的图广度优先遍历
void BFSTraverse(GraphAdjList *GL)
{
int i;
EdgeNode *p;
Queue Q;
for (i = 0; i < GL->numVertexes; i++) {
visited[i] = FALSE;
}
InitQueue(&Q);
for (i = 0; i < GL->numVertexes; i++) {
if (!visited[i]) {
visited[i] = true;
printf("%c", GL->adjList[i].data);
EnQueue(&G, i);
while (!QueueEmpty(&G)) {
DEQueue(&G, i);
p = GL->adjList[i].firstEdge;
while (p) {
if (!visited[p->adjvex]) {
visited[p->adjvex] = true;
printf("%c", GL->adjList[p->adjvex].data);
EnQueue(&G, p->adjvex);
}
p = p->next;
}
}
}
}
}、