提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
邻接矩阵
typedef struct{
int no; 顶点编号
char info;
}VertexType;
typedef struct{
int edges[maxSize][maxSize];
int n, e; 顶点数,边数
VertexType[maxSize];
}MGraph;
邻接表
typedef struct ArcNode{
int adjvex; 边指向的结点
struct ArcNode *nextarc;
int info;
}ArcNode;
typedef struct{
char data;
ArcNode *firstarc;
}VNode;
typedef struct{
VNode adjlist[maxSize];
int n, e;
}AGraph;
强连通图:
当且仅当G中有一个回路,它至少包含每个节点一次
一、基础算法
存储结构:邻接表
-
DFS(类似树先序
int visit[maxSize]; void DFS(AGraph *G, int v){ ArcNode *p; visit[v] = 1; Visit(v); p = G->adjlist[v].firstarc; while(p!=NULL){ if(visit[p->adjvex] == 0){ DFS(G, p->adjvex); } p = p->nextarc; } } void dfs(AGraph *g){ for(int i = 0; i<g->n; i++){ if(visit[i] == 0){ DFS(g, i); } } }
-
BFS(类似树层次
void BFS(AGraph *G, int v, int visit[maxSize]){ ArcNode *p; int que[maxSize], front = 0, rear = 0; int j; Visit(v); visit[v] = 1; rear = (rear + 1) % maxSize; que[rear] = v; while(front != rear){ front = (front + 1) % maxSize; j = que[front]; p = G->adjlist[j].firstarc; while(p != NULL){ if(visit[p->adjvex] == 0){ Visit(p->adjvex); visit[p->adjvex] = 1; rear = (rear + 1) % maxSize; que[rear] = p->adjvex; } p = p->nextarc; } } } void bfs(AGraph *g){ for(int i = 0; i<g->n; i++){ if(visit[i] == 0){ BFS(g, i, visit); } } }
例题
-
求不带权无向连通图G中距离顶点最远的一个顶点
返回广搜最后一个结点
int BFS(AGraph *G, int v){ ArcNode *p; int que[maxSize], front = 0, rear = 0; int visit[maxSize]; int i, j; for(i = 0; i<G->n; i++){ visit[i] = 0; } rear = (rear + 1) % maxSize; que[rear] = v; visit[v] = 1; while(front != rear){ front = (front + 1) % maxSize; j = que[front]; p = G->adjlist[j].firstarc; while(p != NULL){ if(p -> adjvex == 0){ visit[p->adjvex] == 1; rear = (rear + 1) % maxSize; que[rear] = p->adjvex; } p = p->nextarc; } } return j; }
-
判断无向图G是否是一棵树。若是树,返回1,否则返回0
无向图是树:①n-1条边 ②n个顶点 ③连通图
void DFS(AGrapg *G, int v, int &vn, int &en){ ArcNode *p; visit[v] = 1; ++vn; vn顶点计数器 p = G->adjlist[v].firstarc; while(p != NULL){ ++en;边计数器 if(visit[p->adjvex] == 0){ DFS(G, p->adjvex, vn, en); } p = p->nextarc; } } int GisTree(AGraph *G){ int vn = 0, en = 0, i; for(i = 0; i<G->n; ++i){ visit[i] = 0; } DFS(G, 1, vn, en); if(vn == G->n && (G->n-1) == en/2) return 1; return 0; }
-
邻接表判断顶点 i i i和顶点 j j j( i ! = j i!=j i!=j)之间是否有路径
i i i开始深搜,遇到 j j j则有
int dfs(AGraph *G, int i, int j){ int k; for(k = 0; k<G->n; k++){ visit[k] = 0; } DFS(G, i); if(visit[j] == 1) return 1; return 0; }
-
Prim算法
v s e t [ i ] vset[i] vset[i] 顶点是否生成树中
l o w c o s t [ i ] lowcost[i] lowcost[i] 当前生成树到剩余各顶点最短边的权值
void Prim(MGraph g, int v0, int &sum){
int lowcost[maxSize], vset[maxSize], v;
int i, j, k, min;
v = v0;
for(int i = 0; i<g.n; i++){
vset[i] = 0;
lowcost[i] = g.edges[v0][i];
}
vset[v0] = 1;
sum = 0;
for(i = 0; i<g.n-1; i++){
//找相邻最小边
min = INF;
for(j = 0; j<g.n; j++){
if(vset[j] == 0 && lowcost[j] < min){
min = lowcost[j];
k = j;
}
}
v = k;
vset[k] = 1;
sum += min;
// 更新/维护
for(j = 0; j<g.n; j++){
if(vset[j] == 0 && g.edges[v][j] < lowcost[j]){
lowcost[j] = g.edges[v][j];
}
}
}
}
Kruskal算法
typedef struct{
int a, b;
int w;
}Road;
Road road[maxSize];
int v[maxSize];
int getRoot(int a){
while(a != v[a])
a = v[a];
return a;
}
void Kruskal(MGraph g, int &sum, Road road[]){
int i;
int N, E, a, b;
N = g.n;E = g.e;sum = 0;
for(i = 0; i<N; i++){
v[i] = i;
}
sort(road, E);
for(i = 0; i<E; i++){
a = getRoot(road[i].a);
b = getRoot(road[i].b);
if(a != b){
v[a] = b;
sum += road[i].w;
}
}
}
Dijkstra算法
d i s t [ v i ] dist[v_i] dist[vi] 当前已找到的从v0到每个终点vi的最短路径总长度
p a t h [ v i ] path[v_i] path[vi] 从v0到vi最短路径上vi的前一个顶点
s e t [ v i ] set[v_i] set[vi] 标记数组
void Dijkstra(MGraph g, int v, int dist[], int path[]){
int set[maxSize];
int min, i, j, u;
// Initialize
for(i = 0; i<g.n; i++){
dist[i] = g.edges[v][i];
set[i] = 0;
if(g.edges[v][i] < INF)
path[i] = v;
else
path[i] = -1;
}
set[v] = 1;
path[v] = -1;
// Find shortest path
for(i = 0; i<g.n-1; i++){
min = INF;
// Find a node which dist is shortest
for(j = 0; j<g.n; j++){
if(set[j] == 0 && dist[j] < min){
u= j;
min = dist[j];
}
}
set[u] = 1;
// Update dist[] and path[]
for(j = 0; j<g.n; j++){
if(set[j] == 0 && dist[u] + g.edges[u][j] < dist[j]){
dist[j] = dist[u] + g.edges[u][j];
path[j] = u;
}
}
}
}
Floyd算法
d i s t [ v i ] dist[v_i] dist[vi] 当前已找到的任意两顶点的最短路径长度
p a t h [ v i ] path[v_i] path[vi] 从v0到vi最短路径上vi的前一个顶点
void Floyd(MGraph *g, int path[][maxSize], int dist[][maxSize]){
int i, j, k;I
// Initialize
for(i = 0; i<g->n; i++){
for(j = 0; j<g->n; j++){
dist[i][j] = g->edges[i][j];
path[i][j] = -1;
}
}
// Find and update
for(k = 0; k<g->n; k++){
for(i = 0; i<g->n; i++){
for(j = 0; j<g->n; j++){
if(dist[i][k] + dist[k][j]<dist[i][j]){
dist[i][j] = dist[i][k] + dist[k][j];
path[i][j] = k;
}
}
}
}
}
void printPath(int u, int v, int path[][maxSize], int dist[][maxSize]){
if(dist[u][v] == INF)
return;
else{
if(path[u][v] == -1){
printf("<%d,%d>", u, v);
}else{
int mid = path[u][v];
printPath(u, mid, path, dist);
printPath(mid, v, path, dist);
}
}
}
拓扑排序
typedef struct{
int data;
int count;
ArcNode* first;
}VNode;
int TopSort(AGraph *G){
int i, j, n = 0;
int stack[maxSize], top = -1;
ArcNode *p;
// Initialize
for(i = 0; i<G->n; i++){
if(G->adjList[i].count == 0){
top++;
stack[top] = i;
}
}
// Find
while(top != -1){
i = stack[top];
top--;
n++;
cout<<i<<" ";
p = G->adjList[i].first;
while(p != NULL){
j = p->adjV;
(G->adjList[j].count)--;
if(G->adjList[j].count == 0){
top++;
stack[top] = j;
}
p = p->next;
}
}
}
二、综合应用题
-
附加
已并入的顶点 dist[a], pre[a] dist[b] , pre[b] dist[c], pre[c] dist[d], pre[d] dist[e], pre[e] dist[f], pre[f] a - 2,- 5,- - - - a, b 3,b 5,b a, b, c 5,b 9,c 6,c a, b, c, d 9,c 6,c a, b, c, d, f 9,c a, b, c, d, f, e
-
- 用邻接矩阵表示图时,矩阵元素的个数与顶点个数是否有关?与边的条数是否有关?
与顶点个数有关 边的条数无关
-
请回答关于图的下列问题:
-
有n个顶点的有向强连通图最多有多少条边?最少有多少条边?
最多: 两两相连 n(n-1)
最少: 围成一圈 n -
对于一个有向图,不用拓扑排序,实现判断图中是否存在经过给定顶点v0的环的算法
思路:
深搜邻接表,回溯(因为下次寻找路径,路径中的结点可能重复遇到,因此要还原现场)bool DFS(AGraph *G, int v, bool visited[]){ bool flag; ArcNode *p; visited[v] = true; for(p = G->adjList[v].first; p!=NULL; p = p->next){ if(vistied[p->adjV] == true) return true; else flag = DFS(G, p->adjV, visited); if(flag == true) return true; visited[p->adjV] = 0; } return false; }
-
-
设G=(V,E)以邻接表存储,如图所示,试画出图的深度优先和广度优先生成树
- 写出遍历序列:
深度优先遍历序列:
<1,2> <2,3> < 3,4> <4,5>
广度优先遍历序列
<1,2> <1,3> <1,4> <2,5> - 由边的序列画出搜索生成树
深度优先生成树:
广度优先生成树:
- 写出遍历序列:
-
如图所示为一个地区的通信网,边表示城市间的通信线路,边上的权表示架设线路花费的代价,如何选择能沟通每个城市且总代价最省的n-1条线路,画出所有可能的选择。
总结
提示:这里对文章进行总结: