1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
| #include <stdio.h> #include <stdlib.h> #include <string.h> //自定义 #define INF INT_MAX #define MAXVEX 30 //typedef char VertexType; typedef struct vertex { int adjvex; //顶点编号 char data[10]; //顶点的信息,可有可无,这里定义为char[10] } VType; //顶点的数据类型
typedef struct graph { int n, e; //n,e,为图中存在的顶点和边的个数 VType vexs[MAXVEX]; //顶点集合 int edges[MAXVEX][MAXVEX]; //邻接矩阵 } MGraph; //图的数据类型 //图的邻接表 typedef char VertexType[10]; // typedef struct edgenode { int adjvex; //相邻点序号 int weight; //边的权值 struct edgenode *nextarc; //指向下一条边的顶点 } ArcNode; //每个顶点建立的单链表中边结点的数据类型
typedef struct vexnode { VertexType data; //存放顶点信息 ArcNode *firstarc; //作为头指针指向第一条边结点 } VHeadNode; //单链表的头结点数据类型 typedef struct { int n, e; //,n,e为实际的顶点数和边数 VHeadNode adjlist[MAXVEX]; //单链表头结点数组 } ALGraph; //图的邻接表数据类型
//---------------------------------------------------------------- //邻接矩阵相关的算法 /*已知邻接矩阵数组A,顶点数n,边数e,建立图G的邻接矩阵存储结构*/ void CreatGraph(MGraph &g, int A[][MAXVEX], int n, int e) { int i, j; g.n = n; g.e = e; for (i = 0; i < n; i++) for (j = 0; j < n; j++) g.edges[i][j] = A[i][j]; }
//求无向图顶点的度 int Degree1(MGraph g, int v) { int i, d = 0; if (v < 0 || v >= g.n) //判断边是否合法 return -1; for (i = 0; i < g.n; i++) { if (g.edges[v][i] > 0 && g.edges[v][i] < INF) //计算度 d++; } return d; }
//数组存储的有向图的顶点的度的计算 int Degree2(MGraph g, int v) { int i, d1 = 0, d2 = 0, d; if (v < 0 || v >= g.n) return -1; for (i = 0; i < g.n; i++) if (g.edges[v][i] > 0 && g.edges[v][i] < INF) d1++; //以v为开始的度,就是出度 for (i = 0; i < g.n; i++) if (g.edges[i][v] > 0 && g.edges[i][v] < INF) d2++; //以v为结束的度,也就是入度 d = d1 + d2; //总的度数 return d; }
//================================================================ //建立图的邻接表算法 /*已知邻接矩阵数组A,顶点数n,边数e,建立图G的邻接矩阵存储结构*/ void CreatGraph2(ALGraph *&G, int A[][MAXVEX], int n, int e) { int i, j; ArcNode *p; //这是结点指针 G = (ALGraph *)malloc(sizeof(ALGraph)); G->n = n; G->e = e; //先确认边和结点的个数 for (i = 0; i < G->n; i++) //将每个头结点的指针域先置空 G->adjlist[i].firstarc = NULL; for (i = 0; i < G->n; i++) //对于每个链表都进行循环赋值插入 for (j = G->n - 1; j >= 0; j--) //对某一个链表进行操作 if (A[i][j] > 0 && A[i][j] < INF) //只要邻接矩阵存在边 { //使用头插法将所有边的信息链接起来 p = (ArcNode *)malloc(sizeof(ArcNode)); //先申请一块新的空间 p->adjvex = j; //让这个边的后值置为j p->weight = A[i][j]; //赋权4给w p->nextarc = G->adjlist[i].firstarc; //再让p指向i个链表的第一个结点 G->adjlist[i].firstarc = p; //再让头结点重置为p,这样头结点还是头结点,新的结点实现头插 } }
//销毁图 void DestroyGraph(ALGraph *&G) { int i; ArcNode *pre, *p; for (i = 0; i < G->n; i++) //遍历所有的头结点 { pre = G->adjlist[i].firstarc; //通过头结点删除链表 if (pre != NULL) { /*同遍历链表类似,区别在于p_mov每指向某个节点后都将该节点释放
1、释放前要先保存下一个节点,释放后备份恢复给p_mov,否则释放了当前节点,下一个节点的地址就将失去; 2、依次将所有节点释放后,最后返回NULL(标示释放完毕)。*/ p = pre->nextarc; //记录后一个结点的位置 while (p != NULL) //释放i个链表 { free(pre); //释放前一个结点 pre = p; //递归,让前驱指针继续移动,直到后继为空 p = pre->nextarc; //后继指针同步移动 } free(pre); //释放最后一个结点 } } free(G); //释放G所指的头头结点数组的内存空间 }
//求无向图顶点的度 int Degree21(ALGraph *G, int v) { int d = 0; ArcNode *p; //创建一个指向结点的指针,便于遍历 if (v < 0 || v > G->n) return -1; p = G->adjlist[v].firstarc; while (p != NULL) //只要统计单链表的长度就行 { d++; p = p->nextarc; } return d; } //有向图的度 int Degree22(ALGraph *G, int v) { int i, d1 = 0, d2 = 0, d; ArcNode *p; // if (v < 0 || v > G->n) return -1; p = G->adjlist[v].firstarc; while (p != NULL) //先一维循环,查找以v为起点的边,也就是出度 { d1++; p = p->nextarc; } for (i = 0; i < G->n; i++) //再二维循环,遍历整个数组 { p = G->adjlist[i].firstarc; while (p != NULL) //查找以v为末尾节点的边,也就是入度 { if (p->adjvex == v) d2++; p = p->nextarc; } } d = d1 + d2; return d; }
//将邻接矩阵g转换为邻接表G void MAtTodj(MGraph g, ALGraph *&G) { int i, j; ArcNode *p; // G = (ALGraph *)malloc(sizeof(ALGraph)); //先建表 for (i = 0; i < g.n; i++) G->adjlist[i].firstarc = NULL; //置空 for (i = 0; i < g.n; i++) //对邻接矩阵进行遍历 for (j = g.n - 1; j >= 0; j--) //这个遍历显然是二重的 if (g.edges[i][j] != 0 && g.edges[i][j] != INF) //对于第i中可取的值,都创建一个新的结点p { p = (ArcNode *)malloc(sizeof(ArcNode)); //申请结点指针类型空间 p->adjvex = j; //记录尾结点的位置 //对这个结点p进行赋值 p->weight = g.edges[i][j]; //赋权 p->nextarc = G->adjlist[i].firstarc; //只要结点值合法,就创建一个结点,采用头插法 G->adjlist[i].firstarc = p; //重置头结点 } G->n = g.n; G->e = g.e; } ////////////////////////////////////////////////////////////////////////////////////////////////////// /*为了防止多次访问,设置标记数组visited[],开始为0,访问后为1 1,深度优先遍历、确定一个开始当我起点,然后开始访问第一个临界点,然后访问第一个临界点的临界点, 对于已经被访问的,直接跳过,然后开始,直到所有的结点都被访问 */ int visited[MAXVEX] = {0}; //先设置一个全局变量 void DFS(ALGraph *G, int v) //深度优先遍历算法 { int w; //标记邻接点的位置 ArcNode *p; //用于遍历 printf("即将访问的是顶点v:%d", v); //访问v顶点 visited[v] = 1; //改变标志位 p = G->adjlist[v].firstarc; //找v的第一个邻接点 while (p != NULL) //找v的所有邻接点 { w = p->adjvex; // { if (visited[w] == 0) //只要w没被访问 DFS(G, w); //就从w出发进行深度优先遍历 p = p->nextarc; //被访问就下一个 } } } /*---------------------------------------------------------------- 2)广度优先算法 指定从v开始,依次访问它所在的链表,也就是访问它的所有的邻接点,然后再从第一个邻接点开始, 重复这样的循环,直到v的最后一个邻接点也被遍历了。*/ void BFS(ALGraph *G, int vi) { int i, v; ArcNode *p; int Q[MAXVEX], front = 0, rear = 0; //定义一个队列Q,初始化Q for (i = 0; i < G->n; i++) //这一步在已经有了全局变量的时候就不用了 visited[i] = 0; //这一步在已经有了全局变量的时候就不用了 printf("现在访问的:%d\t", vi); //输出 visited[i] = 1; //已经访问的结点,要进行置一操作 rear = (rear + 1) % MAXVEX; //初始顶点进队,这里涉及到队列的知识,可以回头复习一下 Q[rear] = vi; //进队,先进先出,所以用队呀 while (front != rear) //只要队列不为空 { front = (front + 1) % MAXVEX; v = Q[front]; //出队顶点v p = G->adjlist[v].firstarc; //对v所在的链表进行遍历,也就是查找v的所有的邻接点 while (p != NULL) //只要v的邻接点没有被访问完 { if (visited[p->adjvex] == 0) //如果是访问了visited=0的,就访问它且进队,否则跳过 { printf("现在访问到了:%d\n\t", p->adjvex); //访问 visited[p->adjvex] = 1; //置一 rear = (rear + 1) % MAXVEX; //进队 Q[rear] = p->adjvex; //进队 } p = p->nextarc; //如果visited=1,就跳过,继续后面的访问 } } }
int main() {
ALGraph tu = {4, 1}; ALGraph &G = tu; ALGraph *q; *q = tu; int A[][30] = { {1111}, {0000}, {1111}, {0000}}; int(*p)[30] = A; int n = 4; int e = 8; CreatGraph2(q, p, n, e); DFS(q, 1); }
|