图:存储结构、深度优先遍历以及广度优先遍历
2017-04-09 16:00
726 查看
图:记录关系、联系,由数个点Vertex、数条边Edge组成。
同构 Isomorphism 英[ˌaɪsəʊ’mɔ:fɪzəm] :两张图的连接方式一样。
如图,记录(0,1) (0,3) (0,4)
无向图的边数组是个对称矩阵(aij=aji)。
顶点vi的度:vi所在行的元素之和
有向图讲究入度和出度。顶点vi的入度是vi所在列的元素之和,出度是所在行的元素之和
矩阵的值也可以是边的权重。
以下图为例。从A点出发,做上表示走过的记号。我们给自己定一个原则,在没有碰到重复顶点的情况下,始终往右手边走。于是走向B,接着C、D、E、F。继续往右手边走,发现A点已经访问过了,此时退回F点,走向从右数的第二个通道到达顶点G,G有三条通道,B和D都走过,所以走向H,H的两条通道D和E都走过。
此时是否已经遍历了所有顶点呢?没有。所以按原路返回,回到G,没有未走过的通道,回到F,没有未走过的通道,回到E,有一条通往H,验证后也是走过的。回到D,有三条道未走过,一条条来。走到I,这是个未标记过的顶点,标记下来。继续返回直到返回顶点A,确认完成遍历任务,找到了所有的9个顶点。
将这个过程化为上图。这其实就是一个递归的过程。这里以连通图为例,如果是非连通图,需要对它的连通分量分别进行深度优先遍历。
图的存储方式是邻接矩阵:
图的存储方式是邻接表
对于n个顶点e条边的图来说,邻接矩阵由于是二维数组,要查找每个顶点的邻接点需要访问矩阵中的所有元素,因此都需要O(n2)的时间。
而邻接表做存储结构时,找邻接点所需时间取决于顶点和边的数量,所以是O(n+e),显然对于点多边少的稀疏图,邻接表结构使得算法在时间效率上大大提高。
一、把起點放入queue。
二、重複下述兩步驟,直到queue裡面沒有東西為止:
甲、從queue當中取出一點。
乙、找出跟此點相鄰的點,並且尚未遍歷的點,
通通(依照編號順序)放入queue。
只觀察離開 queue 的時刻,可以發現 BFS 優先走遍距離起點最近之處,優先讓 BFS Tree 變得寬廣,因而得名 Breadth-first Search 。這個遍歷順序能夠解決許多圖論問題!
时间复杂度:使用的資料結構為 adjacency matrix 的話,可以以 O(V^2) 時間遍歷整張圖;使用 adjacency lists 的話,可以以 O(V+E) 時間遍歷整張圖。 V 是圖上的點數, E 是圖上的邊數。
同构 Isomorphism 英[ˌaɪsəʊ’mɔ:fɪzəm] :两张图的连接方式一样。
图的存储结构:
阵列
记录所有的点与所有的边。直观、节省空间、但不适于计算。如图,记录(0,1) (0,3) (0,4)
邻接矩阵 adjacency matrix
无向图的边数组是个对称矩阵(aij=aji)。
顶点vi的度:vi所在行的元素之和
有向图讲究入度和出度。顶点vi的入度是vi所在列的元素之和,出度是所在行的元素之和
矩阵的值也可以是边的权重。
typedef struct{ VertexType vexes[MAX]; //顶点表 EdgeType arc[MAX][MAX]; //邻接矩阵 int numVertexes,numEdges; //顶点数,边数 } MGraph;
邻接表 adjacency lists
把一張圖上的點依序標示編號。每一個點,後方串連所有相鄰的點typedef char VertexType; //顶点类型 typedef int EdgeType; //边上的权值类型 typedef struct EdgeNode{ //边表结点 int adjvex; EdgeType weight; struct EdgeNode *next; } EdgeNode; typedef struct VertexNode{ //顶点表结点 VertexType data; EdgeNode *firstedge; } VertexNode, AdjList[MAX]; typedef struct{ AdjList adjList; int numVertexes,numEdges; } GraphAdjList;
图的遍历:
两种遍历算法:深度优先遍历 Depth First Search,广度优先遍历 Breadth First Search,。深度优先遍历
从图中某个顶点出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直到图中所有和v有路径相同的顶点都被访问到。以下图为例。从A点出发,做上表示走过的记号。我们给自己定一个原则,在没有碰到重复顶点的情况下,始终往右手边走。于是走向B,接着C、D、E、F。继续往右手边走,发现A点已经访问过了,此时退回F点,走向从右数的第二个通道到达顶点G,G有三条通道,B和D都走过,所以走向H,H的两条通道D和E都走过。
此时是否已经遍历了所有顶点呢?没有。所以按原路返回,回到G,没有未走过的通道,回到F,没有未走过的通道,回到E,有一条通往H,验证后也是走过的。回到D,有三条道未走过,一条条来。走到I,这是个未标记过的顶点,标记下来。继续返回直到返回顶点A,确认完成遍历任务,找到了所有的9个顶点。
将这个过程化为上图。这其实就是一个递归的过程。这里以连通图为例,如果是非连通图,需要对它的连通分量分别进行深度优先遍历。
图的存储方式是邻接矩阵:
typedef int Boolean; Boolean visited[MAX]; void DFS(MGraph G,int i){ int j; visited[i]=TRUE; printf("%c ",G.vexs[i]); //打印顶点,也可以进行其他操作 for(j=0;j<G.numVertexes;j++){ if(G.arc[i][j]==1 && !visited[j]) DFS(G,j); //对未访问的邻接顶点递归调用 } } void DFSTraverse(MGraph G){ int i; for(i=0;i<G.numVertexes;i++){ visited[i]=FALSE; //初始化所有顶点状态为未访问 } for(i=0;i<G.numVertexes;i++){ if(!visited[i]){ //对未访问过的顶点调用DFS,如果是连通图,只会执行一次 DFS(G,i); } } }
图的存储方式是邻接表
void DFS(GraphAdjList GL, int i){ EdgeNode *p; visited[i]=TRUE; printf("%c ",GL->adjList[i].data); p=GL->adjList[i].firstedge; while(p!=NULL){ if(!visited[p->adjvex]){ DFS(GL,p->adjvex); } p=p->next; } } void DFSTraverse(GraphAdjList GL){ int i; for(i=0;i<GL->numVertexes;i++){ visited[i]=FALSE; //初始化所有顶点状态为未访问 } for(i=0;i<GL->numVertexes;i++){ if(!visited[i]){ //对未访问过的顶点调用DFS,如果是连通图,只会执行一次 DFS(G,i); } } }
对于n个顶点e条边的图来说,邻接矩阵由于是二维数组,要查找每个顶点的邻接点需要访问矩阵中的所有元素,因此都需要O(n2)的时间。
而邻接表做存储结构时,找邻接点所需时间取决于顶点和边的数量,所以是O(n+e),显然对于点多边少的稀疏图,邻接表结构使得算法在时间效率上大大提高。
广度优先遍历
(依照編號順序)不斷找出尚未遍歷的點當作起點,進行下述行為:一、把起點放入queue。
二、重複下述兩步驟,直到queue裡面沒有東西為止:
甲、從queue當中取出一點。
乙、找出跟此點相鄰的點,並且尚未遍歷的點,
通通(依照編號順序)放入queue。
只觀察離開 queue 的時刻,可以發現 BFS 優先走遍距離起點最近之處,優先讓 BFS Tree 變得寬廣,因而得名 Breadth-first Search 。這個遍歷順序能夠解決許多圖論問題!
时间复杂度:使用的資料結構為 adjacency matrix 的話,可以以 O(V^2) 時間遍歷整張圖;使用 adjacency lists 的話,可以以 O(V+E) 時間遍歷整張圖。 V 是圖上的點數, E 是圖上的邊數。
bool adj[9][9]; // 一張圖,資料結構為adjacency matrix。 bool visit[9]; // 記錄圖上的點是否遍歷過,有遍歷過為true。 void BFS() { // 建立一個queue。 queue<int> q; // 全部的點都初始化為尚未遍歷 for (int i=0; i<9; i++) visit[i] = false; for (int k=0; k<9; k++) if (!visit[k]) { 一、把起點放入queue。 q.push(k); visit[k] = true; // 二、重複下述兩點,直到queue裡面沒有東西為止: while (!q.empty()) { // 甲、從queue當中取出一點。 int i = q.front(); q.pop(); // 乙、找出跟此點相鄰的點,並且尚未遍歷的點, // 依照編號順序通通放入queue。 for (int j=0; j<9; j++) if (adj[i][j] && !visit[j]) { q.push(j); visit[j] = true; } } } }
相关文章推荐
- C语言以邻接矩阵为存储结构的图的构造以及广度优先,深度优先遍历
- C语言以邻接表为存储结构的图的构造以及广度优先,深度优先遍历
- C++编程练习(9)----“图的存储结构以及图的遍历“(邻接矩阵、深度优先遍历、广度优先遍历)
- C++编程练习(9)----“图的存储结构以及图的遍历“(邻接矩阵、深度优先遍历、广度优先遍历)
- 广度优先遍历,深度优先遍历,拓扑排序(十字链表存储结构)
- 图的存储以及深度优先以及广度优先遍历
- 存储结构与邻接矩阵,深度优先和广度优先遍历及Java实现
- 树的存储结构和图的存储结构以及图的深度优先DFS搜索和BFS广度优先搜索
- 图的存储以及深度优先和广度优先
- 【图】图的邻接矩阵存储和广度、深度优先遍历
- 图的邻接矩阵存储 深度优先遍历 广度优先遍历 C语言实现
- 【数据结构实验】图的深度优先/广度优先遍历
- 数据结构之深度优先,广度优先遍历
- 图的邻接表存储 深度优先遍历 广度优先遍历 C语言实现
- 数据结构图的数组表示法以及深度,广度遍历
- 图的邻接表存储 深度优先遍历 广度优先遍历 C语言实现
- 数据结构:图的遍历--深度优先、广度优先
- 数据结构--图--图的数组存储表示,深度优先搜索遍历和广度优先搜索遍历
- 图的邻接矩阵存储:深度、广度优先遍历
- 图(图的存储和图的遍历即深度优先搜索遍历图和广度优先搜索遍历图)