数据结构6-图

该文章仅为本人考研复习之用,根据记忆整理,如有错误,请多指正。

1.基础概念

①完全图

2.存储及操作

图的存储包含四种存储结构:

2.1邻接矩阵

顺序存储-适合稠密图

#define maxvex 100
typedef char vextype;				//结点表类型
typedef int arctype;				//边表类型
typedef struct Graph{				//邻接矩阵存储法
	vextype vexlist[maxvex];		//顶点表
	arctype arclist[maxvex][maxvex];//邻接矩阵
}Graph;

特点:
①对称矩阵-某图的边个数 = 邻接矩阵中所有1元素/2;
②若图为有向图,则第i行元素1的个数是顶点i的出度,第i列元素1的个数是顶点的入度;
③若邻接矩阵A,则A的n次方[i][j]代表从结点i到结点j长度为n的路径条数

2.2邻接表

顺序存储和链式存储结合-适合稀疏图

#define maxvex 100
typedef char vextype;
typedef int arctype;
//边结点
typedef struct arcnode{
	arctype vexloc;
	struct arcnode *nextarc;
}arcnode;
//顶点结点
typedef struct vexnode{
	vextype data;
	struct arcnode *firstarc;
}vexnode,vexlist[maxvex];
//邻接表
typedef struct Graph{
	vexlist vertices;
	int vexnum,arcnum;
}Graph;

2.3十字链表

有向图的链式存储结构

2.4邻接多重表

无向图的链式存储结构

2.5存储-总结

在上述的四种存储方式中,邻接矩阵和邻接表法存储的边数是现有图结构中边数的两倍,而十字链表法和邻接多重表法存储的边数和图结构中边数相等的。

3.图的遍历

3.1广度优先遍历(BFS)

树是图的一种特殊形式,图的广度优先遍历原理类似于树的层次遍历,但由于图没有树结构的父母孩子结点的单向约束关系,因此需要设置一个数组来标识结点以免被重复访问。

3.1.1基本原理:

①构建一个辅助数组保证每个结点只被访问一遍;构建一个辅助队列进行广度遍历;
②首先访问该节点,并将在辅助数组更改标识‘已访问’,并入队该节点;
③若队列不空,则进行循环:执行出队操作;检查队头结点的所有邻接点
若邻接点被访问过,则跳过;若未访问过,执行步骤②。

bool visited[maxvem];
void BFStransver(Graph G){
	for (i=0;u<G.vexnum;i++) visited[i]=False;
	InitQueue(Q);
	for(i=0;i<G.vexnum;i++) if(!visited[i]) BFS(G,i);
}

void BFS(Graph g,int v){
	visit(v);
	visited[v] = True;
	Enqueue(Q,v);
	while(!Isempty(Q)){
		Dequeue(Q,v);
		for(w=firstneighbor(G,v);w>=0;w=newneighbor(G,v,w)){
			if(!visited[w]){
				visit(w);
				visited[w]=True;
				Enqueue(Q,v);
			}
		}
	}
}
3.1.2性能分析

1、每个结点都要进入队列进行遍历,空间复杂度O(V);
2、时间复杂度:
①邻接表遍历:
遍历节点表以及每个结点后的边表,时间复杂度O(V+E)
②邻接矩阵遍历:
遍历邻接表全部元素,时间复杂度O(V^2)

3.2深度优先遍历(DFS)

3.2.1基本原理

与BFS不同,DFS是递归的,不需要构建辅助队列;
①构建辅助数组
访问节点;访问该节点邻居
③若邻居存在,则重复②;

bool visited[maxvex];

void DFStranverse(Graph G){
	for(i=0;i<G.vexnum;i++) visited[i]=False;
	for(i=0;i<G.vexnum;i++){
		if(!visited[i]) DFS(G,i));
	}
}

void DFS(Graph G, int v){
	visit(v);
	visited[v] = True;
	for(w=firstneighbor(G,w);w>=0;w=nextneighbor(G,v.w)){
		if(!visited[w]) DFS(G,w)
	}
}
3.2.2性能分析

1、空间复杂度:DFS是递归算法,因此空间复杂度是O(V);
2、时间复杂度:
①邻接矩阵:O(V^2);
②邻接表:O(V+E);

3.3遍历-真题

  • 01 设计一个算法,判断一个无向图G是否是一棵树。若是一棵树,则返回true;否则返回false;

思路:树是图的一种特殊形态,“边数+1=节点数”是树区别于图的特殊性质;
基本原理:利用DFS遍历图,得到图的结点和边个数,并与图中边的个数相比较;

int visited[maxvex]={0};//设置辅助数组
//调用递归,根据上述特性判别是否为树结构
void Istree(Graph &G){
	int Vnum=0,Enum=0;
	DFS(G,1,Vnum,Enum,visited);
	if(Vnum==G.vexnum && Vnum==2*(G,vexnum-1)) 
		return true;
	else 
		return false;
}
//深度遍历
void DFS(Graph& G,int v,int& Vnum,int& Enum,int vistied[]){
	visited[v]=1;//访问结点并置结点为已访问状态
	Vnum++;
	for(w=neighbor(G,v);w>=0;w=newneighbor(G,v,w))
	//遍历结点的邻接点,若某一邻接点未访问,则递归
		Enum++;
		if(!visited[w]) 
			DFS(G,w,Vnun,Enum,visited);
}
  • 02写出图的深度优先搜索DFS算法的非递归算法(图用邻接表形式给出)
    原理:非递归则引入栈;首先入栈结点、更改结点访问状态;当栈非空时,出栈,将出栈结点的所有邻接点访问后入栈;重复上述操作;
	//设辅助数组;
	int visited[maxvex] = {0};
	void DFS_ndg(Graph& G,int v){
		InitStack(S);
		//访问结点并更改访问状态
		visited[v] = 1;
		Push(S,v);
		while(!Isempty(S)){
			Pop(S,v);
			for(w=neighbor(G,v);w=0;w=neighbor(G,v,w))
				if(!visited[w]){
					visited[v]=1;
					Push(S,v);
				}
  • 03分别采用基于深度优先遍历和广度优先遍历算法判别以邻接表方式存储的有向图中是否存在有顶点i到顶点j的路径(i!=j)主义算法中设计的图的操作必须在此存储结构上实现;
//辅助数组
int visited[maxvex]={0};
//深度优先遍历有向图找i到j的路径
bool Isroute_dfs(Graph& G,int i,int j){
	int mark = DFS(G,i,j);
	if(!mark) return 1;
	eles return 0; 
}
int DFS(Graph& G, int v, int j){
	if(v!=j){
		visit(v);
		visited[v]=1;
		for(w=neighbor(G,v);w>=0;w=neighbor(G,v,w)){
			if(visited[w])
				DFS(G,w,j)
	}else
		return 1;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,走迷宫游戏是一个非常有意思的课程设计,需要用到许多数据结构算法。以下是一个简单的实现思路: 1. 将迷宫地存储在一个二维数组中,其中 0 表示可以通过的路,1 表示墙壁。 2. 使用栈来实现迷宫的深度优先搜索,从起点开始,不断往前走,直到遇到墙壁或者到达终点。 3. 如果遇到墙壁,则将当前位置出栈,并回溯到上一个位置,继续搜索。 4. 如果到达终点,则输出路径并结束程序。 下面是一个简单的实现代码: ```python class Maze: def __init__(self, maze_map): self.maze_map = maze_map self.width = len(maze_map[0]) self.height = len(maze_map) def get_neighbors(self, pos): x, y = pos neighbors = [] if x > 0 and self.maze_map[y][x-1] == 0: neighbors.append((x-1, y)) if y > 0 and self.maze_map[y-1][x] == 0: neighbors.append((x, y-1)) if x < self.width-1 and self.maze_map[y][x+1] == 0: neighbors.append((x+1, y)) if y < self.height-1 and self.maze_map[y+1][x] == 0: neighbors.append((x, y+1)) return neighbors def find_path(self, start, end): stack = [start] visited = set() while stack: pos = stack[-1] if pos == end: return stack if pos not in visited: visited.add(pos) neighbors = self.get_neighbors(pos) for neighbor in neighbors: if neighbor not in visited: stack.append(neighbor) else: stack.pop() return None maze_map = [ [0, 1, 0, 0, 0, 0, 0, 0], [0, 1, 0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 1, 0], [1, 1, 1, 1, 1, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1, 0], [0, 1, 1, 1, 1, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0], ] maze = Maze(maze_map) start = (0, 0) end = (7, 6) path = maze.find_path(start, end) if path: print(path) else: print("No path found") ``` 这里我们使用了一个 Maze 类来存储迷宫地和实现搜索算法。其中 get_neighbors 方法用来获取一个位置的所有邻居节点,find_path 方法用来实现深度优先搜索。我们首先将起点压入栈中,然后不断从栈中取出最后一个节点进行搜索,如果当前节点是终点,则返回路径;否则将当前节点的所有邻居节点压入栈中。如果当前节点没有邻居节点或者所有邻居节点都已经被访问过,则将当前节点出栈,回溯到上一个节点。 这个实现还比较简单,如果需要实现更高效的算法,可以考虑使用广度优先搜索或者A*算法

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值