图的表示及遍历
图的表示方法通常有四种:
数组表示,邻接表,十字链表,邻接多重表。
邻接表是图的一种链式存储结构。
十字链表是有向图的另一种链式存储结构。
邻接多重表是无向图的一种链式存储结构。
====================================================
邻接表
邻接表中有两种节点,一种是头节点,另一种是表节点,头节点中存储一个顶点的数据和指向链表中的一个节点,表节点中存储当前顶点在图中的位置和指向下一条边或弧的节点,表头节点用链式或顺序结构方式存储,如下图所示就是上一篇文章G2无向图的邻接表表示。
=====================================================
遍历
深度优先搜索是树的先根遍历的推广,它的基本思想是:从图G的某个顶点v0出发,访问v0,然后选择一个与v0相邻且没被访问过的顶点vi访问,再从vi出发选择一个与vi相邻且未被访问的顶点vj进行访问,依次继续。如果当前被访问过的顶点的所有邻接顶点都已被访问,则退回到已被访问的顶点序列中最后一个拥有未被访问的相邻顶点的顶点w,从w出发按同样的方法向前遍历,直到图中所有顶点都被访问。
广度优先搜索是树的按层次遍历的推广,它的基本思想是:首先访问初始点vi,并将其标记为已访问过,接着访问vi的所有未被访问过的邻接点vi1,vi2,…, vin,并均标记已访问过,然后再按照vi1,vi2,…, vin的次序,访问每一个顶点的所有未被访问过的邻接点,并均标记为已访问过,依次类推,直到图中所有和初始点vi有路径相通的顶点都被访问过为止。
深度优先搜索:0->1->3->7->4->2->5->6
广度优先搜索:0->1->2->3->4->5->6->7
=======================================================
1 // mytest.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <stdio.h> 6 #include <stdlib.h> 7 8 #define TRUE 1 9 #define FALSE 0 10 #define OK 1 11 #define ERROR 0 12 #define OVERFLOW -2 13 #define MAX_NUM 20 14 15 typedef int Status; 16 typedef int QElemType; 17 typedef char VexType; 18 19 /* 20 * 邻接表存储结构 21 */ 22 typedef struct EdgeNode 23 { 24 int adjvex; //顶点的位置 25 struct EdgeNode *next; //指向下一条边的指针 26 }EdgeNode, *EdgeLink; 27 28 typedef struct VexNode 29 { 30 VexType data; //顶点数据 31 EdgeNode *firstEdge; //指向第一条依附该顶点的边的指针 32 }VexNode, AdjList[MAX_NUM]; 33 34 typedef struct 35 { 36 AdjList adjList; 37 int vexNum, edgeNum; //顶点数和边数 38 }ALGraph; 39 40 /* 41 * 队列存储结构(用于图的遍历) 42 */ 43 typedef struct QNode 44 { 45 QElemType data; //结点数据 46 struct QNode *next; //指向下一个结点 47 }QNode, *QueuePtr; 48 49 typedef struct 50 { 51 QueuePtr front; //队头指针 52 QueuePtr rear; //队尾指针 53 }LinkQueue; 54 55 /* 56 * 初始化队列 57 */ 58 Status InitQueue(LinkQueue *Q) 59 { 60 Q->front = Q->rear = (QueuePtr) malloc(sizeof(QNode)); 61 if (!Q->front) 62 { 63 exit(OVERFLOW); 64 } 65 Q->front->next = NULL; 66 return OK; 67 } 68 69 /* 70 * 判断队列是否为空 71 */ 72 Status IsEmpty(LinkQueue Q) 73 { 74 if (Q.front->next == NULL) 75 { 76 return TRUE; 77 } 78 else 79 { 80 return FALSE; 81 } 82 } 83 84 /* 85 * 入队 86 */ 87 Status EnQueue(LinkQueue *Q, QElemType e) 88 { 89 QueuePtr p = (QueuePtr) malloc(sizeof(QNode)); 90 if (!p) 91 { 92 exit(OVERFLOW); 93 } 94 p->data = e; 95 p->next = NULL; 96 Q->rear->next = p; 97 Q->rear = p; 98 return OK; 99 } 100 101 /* 102 * 出队 103 */ 104 Status DeQueue(LinkQueue *Q, QElemType *e) 105 { 106 QueuePtr p; 107 if (Q->front == Q->rear) 108 { 109 return ERROR; 110 } 111 p = Q->front->next; 112 *e = p->data; 113 Q->front->next = p->next; 114 if (Q->rear == p) 115 { 116 Q->rear = Q->front; 117 } 118 free(p); 119 return OK; 120 } 121 122 /* 123 * 创建图 124 */ 125 Status CreateGraph(ALGraph *G) 126 { 127 int i, j, k; 128 EdgeLink e; 129 printf("请输入顶点数目和边数:\n"); 130 scanf("%d", &G->vexNum); 131 scanf("%d", &G->edgeNum); 132 getchar(); 133 printf("请输入各顶点的数据:\n"); 134 for (i = 0; i < G->vexNum; i++) 135 { 136 scanf("%c",&G->adjList[i].data); 137 if (G->adjList[i].data == '\n') 138 { 139 i--; 140 continue; 141 } 142 G->adjList[i].firstEdge = NULL; 143 } 144 145 printf("请依次输入边(Vi,Vj)的顶点序号:\n"); 146 for (k = 0; k < G->edgeNum; k++) 147 { 148 scanf("%d", &i); 149 scanf("%d", &j); 150 e = (EdgeLink) malloc(sizeof(EdgeNode)); 151 e->adjvex = j; 152 e->next = G->adjList[i].firstEdge; 153 G->adjList[i].firstEdge = e; 154 e = (EdgeLink) malloc(sizeof(EdgeNode)); 155 e->adjvex = i; 156 e->next = G->adjList[j].firstEdge; 157 G->adjList[j].firstEdge = e; 158 } 159 return OK; 160 } 161 162 int visited[MAX_NUM]; //用于记录遍历状态 163 164 /* 165 * 递归从第i个结点深度优先遍历图 166 */ 167 void DFS(ALGraph G, int i) 168 { 169 EdgeLink p; 170 visited[i] = TRUE; 171 printf("%c ", G.adjList[i].data); 172 p = G.adjList[i].firstEdge; 173 while (p) 174 { 175 if (!visited[p->adjvex]) 176 { 177 DFS(G, p->adjvex); 178 } 179 p = p->next; 180 } 181 } 182 183 /* 184 * 深度优先遍历 185 */ 186 Status DFSTraverse(ALGraph G) 187 { 188 int i; 189 for (i = 0; i < MAX_NUM; i++) 190 { 191 visited[i] = FALSE; 192 } 193 for (i = 0; i < G.vexNum; i++) 194 { 195 if (!visited[i]) 196 { 197 DFS(G, i); 198 } 199 } 200 return OK; 201 } 202 203 /* 204 * 广度优先遍历 205 */ 206 Status BFSTraverse(ALGraph G) 207 { 208 int i; 209 EdgeLink p; 210 LinkQueue Q; 211 InitQueue(&Q); 212 for (i = 0; i < MAX_NUM; i++) 213 { 214 visited[i] = FALSE; 215 } 216 for (i = 0; i < G.vexNum; i++) 217 { 218 if (!visited[i]) 219 { 220 visited[i] = TRUE; 221 printf("%c ", G.adjList[i].data); 222 EnQueue(&Q, i); 223 while (!IsEmpty(Q)) 224 { 225 DeQueue(&Q, &i); 226 p = G.adjList[i].firstEdge; 227 while (p) 228 { 229 if (!visited[p->adjvex]) 230 { 231 visited[p->adjvex] = TRUE; 232 printf("%c ", G.adjList[p->adjvex].data); 233 EnQueue(&Q, p->adjvex); 234 } 235 p = p->next; 236 } 237 } 238 } 239 } 240 return OK; 241 } 242 243 int main() 244 { 245 ALGraph G; 246 CreateGraph(&G); 247 printf("深度优先遍历:"); 248 DFSTraverse(G); 249 printf("\n广度优先遍历:"); 250 BFSTraverse(G); 251 printf("\n"); 252 }