天勤2022数据结构(六)图

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

邻接矩阵

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中有一个回路,它至少包含每个节点一次

一、基础算法

存储结构:邻接表

  1. 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);
    		}
    	}
    }
    
  2. 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);
    		}
    	}
    }
    

    例题

    1. 求不带权无向连通图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;
      }
      

    2. 判断无向图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;
      }
      

    3. 邻接表判断顶点 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, b3,b5,b
    a, b, c5,b9,c6,c
    a, b, c, d9,c6,c
    a, b, c, d, f9,c
    a, b, c, d, f, e

    • 用邻接矩阵表示图时,矩阵元素的个数与顶点个数是否有关?与边的条数是否有关?

    与顶点个数有关 边的条数无关

  1. 请回答关于图的下列问题:

    1. 有n个顶点的有向强连通图最多有多少条边?最少有多少条边?

      最多: 两两相连    n(n-1)
      最少: 围成一圈    n

    2. 对于一个有向图,不用拓扑排序,实现判断图中是否存在经过给定顶点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;
      }
      
  2. 设G=(V,E)以邻接表存储,如图所示,试画出图的深度优先和广度优先生成树
    在这里插入图片描述

    1. 写出遍历序列
      深度优先遍历序列:
      <1,2> <2,3> < 3,4> <4,5>
      广度优先遍历序列
      <1,2> <1,3> <1,4> <2,5>
    2. 由边的序列画出搜索生成树
      深度优先生成树:
      深度优先生成树
      广度优先生成树:广度优先生成树
  3. 如图所示为一个地区的通信网,边表示城市间的通信线路,边上的权表示架设线路花费的代价,如何选择能沟通每个城市且总代价最省的n-1条线路,画出所有可能的选择。在这里插入图片描述

总结

提示:这里对文章进行总结:

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值