图邻接链表基本操作--广度优先、深度优先、拓扑排序
2013-04-02 18:36
507 查看
和树的遍历相似,若从图中某顶点出发访遍图中每个顶点,且每个顶点仅访问一次,此过程称为图的遍历(Traversing
Graph)。图的遍历算法是求解图的连通性问题、拓扑排序和求关键路径等算法的基础。图的遍历顺序有两种:深度优先搜索(DFS)和广度优先搜索(BFS)。对每种搜索顺序,访问各顶点的顺序也不是唯一的。
1、邻接表及逆邻接表的存储方法
(1)定义
邻接表是图的一种链式存储结构。类似于树的孩子链表表示法。在邻接表中为图中每个顶点建立一个单链表,用单链表中的一个结点表示依附于该顶点的一条边(或表示以该顶点为弧尾的一条弧),称为边(或弧)结点。特征如下:
1) 为每个顶点建立一个单链表,
2) 第i个单链表中包含顶点Vi的所有邻接顶点。
把同一个顶点发出的边链接在同一个边链表中,链表的每一个结点代表一条边,叫做表结点(边结点),邻接点域adjvex保存与该边相关联的另一顶点的顶点下标 , 链域nextarc存放指向同一链表中下一个表结点的指针,数据域info存放边的权。边链表的表头指针存放在头结点中。头结点以顺序结构存储,其数据域data存放顶点信息,链域firstarc指向链表中第一个顶点。
1、广度优先遍历的递归定义
设图G的初态是所有顶点均未访问过。在G中任选一顶点v为源点,则广度优先遍历可以定义为:首先访问出发点v,接着依次访问v的所有邻接点w1,w2,…,wt,然后再依次访问与wl,w2,…,wt邻接的所有未曾访问过的顶点。依此类推,直至图中所有和源点v有路径相通的顶点都已访问到为止。此时从v开始的搜索过程结束。
若G是连通图,则遍历完成;否则,在图C中另选一个尚未访问的顶点作为新源点继续上述的搜索过程,直至G中所有顶点均已被访问为止。
广度优先遍历类似于树的按层次遍历。采用的搜索方法的特点是尽可能先对横向进行搜索,故称其为广度优先搜索(Breadth-FirstSearch)。相应的遍历也就自然地称为广度优先遍历。
2、广度优先搜索过程
在广度优先搜索过程中,设x和y是两个相继要被访问的未访问过的顶点。它们的邻接点分别记为x1,x2,…,xs和y1,y2,…,yt。
为确保先访问的顶点其邻接点亦先被访问,在搜索过程中使用FIFO队列来保存已访问过的顶点。当访问x和y时,这两个顶点相继入队。此后,当x和y相继出队时,我们分别从x和y出发搜索其邻接点x1,x2,…,xs和y1,y2,…,yt,对其中未访者进行访问并将其人队。这种方法是将每个已访问的顶点人队,故保证了每个顶点至多只有一次人队。
1.深度优先遍历的递归定义
假设给定图G的初态是所有顶点均未曾访问过。在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。
图的深度优先遍历类似于树的前序遍历。采用的搜索方法的特点是尽可能先对纵深方向进行搜索。这种搜索方法称为深度优先搜索(Depth-First Search)。相应地,用此方法遍历图就很自然地称之为图的深度优先遍历
2.基本实现思想:
(1)访问顶点v;
(2)从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;
(3)重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。
3、拓扑排序是对有向无环图的一种排序。表示了顶点按边的方向出现的先后顺序。如果有环,则无法表示两个顶点的先后顺序。
在现实生活中,也会有不少应用例子,比如学校课程布置图,要先修完一些基础课,才可以继续修专业课。
一个简单的求拓扑排序的算法:首先要找到任意入度为0的一个顶点,删除它及所有相邻的边,再找入度为0的顶点,以此类推,直到删除所有顶点。顶点的删除顺序即为拓扑排序。
代码如下:
Graph)。图的遍历算法是求解图的连通性问题、拓扑排序和求关键路径等算法的基础。图的遍历顺序有两种:深度优先搜索(DFS)和广度优先搜索(BFS)。对每种搜索顺序,访问各顶点的顺序也不是唯一的。
1、邻接表及逆邻接表的存储方法
(1)定义
邻接表是图的一种链式存储结构。类似于树的孩子链表表示法。在邻接表中为图中每个顶点建立一个单链表,用单链表中的一个结点表示依附于该顶点的一条边(或表示以该顶点为弧尾的一条弧),称为边(或弧)结点。特征如下:
1) 为每个顶点建立一个单链表,
2) 第i个单链表中包含顶点Vi的所有邻接顶点。
把同一个顶点发出的边链接在同一个边链表中,链表的每一个结点代表一条边,叫做表结点(边结点),邻接点域adjvex保存与该边相关联的另一顶点的顶点下标 , 链域nextarc存放指向同一链表中下一个表结点的指针,数据域info存放边的权。边链表的表头指针存放在头结点中。头结点以顺序结构存储,其数据域data存放顶点信息,链域firstarc指向链表中第一个顶点。
1、广度优先遍历的递归定义
设图G的初态是所有顶点均未访问过。在G中任选一顶点v为源点,则广度优先遍历可以定义为:首先访问出发点v,接着依次访问v的所有邻接点w1,w2,…,wt,然后再依次访问与wl,w2,…,wt邻接的所有未曾访问过的顶点。依此类推,直至图中所有和源点v有路径相通的顶点都已访问到为止。此时从v开始的搜索过程结束。
若G是连通图,则遍历完成;否则,在图C中另选一个尚未访问的顶点作为新源点继续上述的搜索过程,直至G中所有顶点均已被访问为止。
广度优先遍历类似于树的按层次遍历。采用的搜索方法的特点是尽可能先对横向进行搜索,故称其为广度优先搜索(Breadth-FirstSearch)。相应的遍历也就自然地称为广度优先遍历。
2、广度优先搜索过程
在广度优先搜索过程中,设x和y是两个相继要被访问的未访问过的顶点。它们的邻接点分别记为x1,x2,…,xs和y1,y2,…,yt。
为确保先访问的顶点其邻接点亦先被访问,在搜索过程中使用FIFO队列来保存已访问过的顶点。当访问x和y时,这两个顶点相继入队。此后,当x和y相继出队时,我们分别从x和y出发搜索其邻接点x1,x2,…,xs和y1,y2,…,yt,对其中未访者进行访问并将其人队。这种方法是将每个已访问的顶点人队,故保证了每个顶点至多只有一次人队。
1.深度优先遍历的递归定义
假设给定图G的初态是所有顶点均未曾访问过。在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。
图的深度优先遍历类似于树的前序遍历。采用的搜索方法的特点是尽可能先对纵深方向进行搜索。这种搜索方法称为深度优先搜索(Depth-First Search)。相应地,用此方法遍历图就很自然地称之为图的深度优先遍历
2.基本实现思想:
(1)访问顶点v;
(2)从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;
(3)重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。
3、拓扑排序是对有向无环图的一种排序。表示了顶点按边的方向出现的先后顺序。如果有环,则无法表示两个顶点的先后顺序。
在现实生活中,也会有不少应用例子,比如学校课程布置图,要先修完一些基础课,才可以继续修专业课。
一个简单的求拓扑排序的算法:首先要找到任意入度为0的一个顶点,删除它及所有相邻的边,再找入度为0的顶点,以此类推,直到删除所有顶点。顶点的删除顺序即为拓扑排序。
代码如下:
#include<iostream> #include<queue> #include<stack> #include<malloc.h> using namespace std; #define MAXSIZE 10 struct Vertex { char key; Vertex *next; }; struct Graphic { Vertex *vArray; int *indegree; int vertexNum; int size; }; class MyGraph { public: MyGraph(); void GraphInit(char edge[][2],int edgelen,char *vertexs,int verlen); void GraphEdgeInsert(char startkey,int endkey); Vertex* GraphVertexSearch(char key,int &location); int GraphOutDegree(char key); int GraphInDegree(char key); void GraphBFS(); void GraphDFS(); void GraphDFSRecur(); void DFSRecur(int vnum,bool* verflag); void GraphTopSort(); private: Graphic *graph; }; MyGraph::MyGraph() { graph = (Graphic*)malloc(sizeof(Graphic)); graph->vArray = (Vertex*)malloc(sizeof(Vertex)*MAXSIZE); graph->indegree = (int*)malloc(sizeof(int)*MAXSIZE); for(int i = 0; i < MAXSIZE;i++) { graph->vArray[i].key = NULL; graph->vArray[i].next = NULL; graph->indegree[i] = 0; } graph->vertexNum = 0; graph->size = MAXSIZE; } void MyGraph::GraphInit(char edge[][2],int edgelen,char *vertexs,int verlen) { int i; if(verlen > graph->size) { graph->vArray = (Vertex*)realloc(graph->vArray,sizeof(Vertex)*(graph->size + verlen)); graph->indegree = (int*)realloc(graph->indegree,sizeof(int)*(graph->size + verlen)); graph->size += verlen; } for(i = 0; i < verlen; i++) { graph->vArray[i].key = vertexs[i]; } graph->vertexNum = verlen; for(i = 0; i < edgelen; i++) { GraphEdgeInsert(edge[i][0],edge[i][1]); } } void MyGraph::GraphEdgeInsert(char startkey,int endkey) { int location; Vertex *result = GraphVertexSearch(startkey,location); Vertex *newnode = (Vertex*)malloc(sizeof(Vertex)); newnode->key = endkey; if(result == NULL) { if(graph->size == graph->vertexNum) { graph->vArray = (Vertex*)realloc(graph->vArray,sizeof(Vertex)*(graph->size + MAXSIZE)); graph->size += MAXSIZE; } result = &(graph->vArray[graph->vertexNum]); result->key = startkey; } GraphVertexSearch(endkey,location); newnode->next = result->next; result->next = newnode; graph->indegree[location]++; } Vertex* MyGraph::GraphVertexSearch(char key,int &location) { for(location = 0;location < graph->vertexNum; location++) { if(graph->vArray[location].key == key) return &(graph->vArray[location]); } return NULL; } int MyGraph::GraphOutDegree(char key) { int outdegree = 0; int i; for(i = 0; i < graph->vertexNum; i++) { if(graph->vArray[i].key == key) break; } if(i != graph->vertexNum) { Vertex *temp = &(graph->vArray[i]); while(temp->next != NULL) { temp = temp->next; outdegree++; } } return outdegree; } int MyGraph::GraphInDegree(char key) { int indegree = 0; Vertex *temp; for(int i = 0;i < graph->vertexNum; i++) { if(graph->vArray[i].key != key) { temp = graph->vArray[i].next; while(temp != NULL) { if(temp->key == key) { indegree++; break; //默认一个节点到另一个节点没有直接的两条或两条以上的边 } temp = temp->next; } } } return indegree; } void MyGraph::GraphBFS() { if(graph->vertexNum > 0) { bool *vertexflag = (bool*)malloc(sizeof(bool)*graph->vertexNum); int i; for(i = 0; i < graph->vertexNum; i++) vertexflag[i] = false; int vertexnum = 0; Vertex* temp,*element; queue<Vertex*> queue; cout<<"The result of BFS : "; while(vertexnum < graph->vertexNum) { if(vertexflag[vertexnum] == false) queue.push(&(graph->vArray[vertexnum])); while(!queue.empty()) { temp = queue.front(); queue.pop(); cout<<temp->key<<" "; temp = temp->next; while(temp != NULL) { GraphVertexSearch(temp->key,i); if(vertexflag[i] == false) { vertexflag[i] = true; element = &(graph->vArray[i]); queue.push(element); } temp = temp->next; } } vertexnum++; } cout<<endl; return; } cout<<"Contain Nothing!"<<endl; } void MyGraph::GraphDFS() { if(graph->vertexNum > 0) { bool *vertexflag = (bool*)malloc(sizeof(bool)*graph->vertexNum); int i; for(i = 0; i < graph->vertexNum; i++) vertexflag[i] = false; Vertex* temp; stack<Vertex*> vstack; int vertexnum = 0; cout<<"The result of DFS : "; while(vertexnum < graph->vertexNum) { if(vertexflag[vertexnum] == false) vstack.push(&(graph->vArray[vertexnum])); while(!vstack.empty()) { temp = vstack.top(); vstack.pop(); if(temp->next != NULL) vstack.push(temp->next); GraphVertexSearch(temp->key,i); if(vertexflag[i] == false) { cout<<temp->key<<" "; if(graph->vArray[i].next != NULL) vstack.push(graph->vArray[i].next); vertexflag[i] = true; } } vertexnum++; } cout<<endl; return; } cout<<"Contain Nothing!"<<endl; } void MyGraph::GraphDFSRecur() { bool *verflag = (bool*)malloc(sizeof(bool)*graph->vertexNum); int i; for(i = 0; i < graph->vertexNum; i++) verflag[i] = false; cout<<"The result of DFSRecur : "; i = 0; while(i < graph->vertexNum) { if(verflag[i] == false) DFSRecur(i,verflag); i++; } cout<<endl; } void MyGraph::DFSRecur(int vnum,bool* verflag) { int i; cout<<graph->vArray[vnum].key<<" "; verflag[vnum] = true; Vertex* temp = graph->vArray[vnum].next; while(temp != NULL) { GraphVertexSearch(temp->key,i); if(verflag[i] == false) { DFSRecur(i,verflag); } temp = temp->next; } } void MyGraph::GraphTopSort() { int i,location; int vexnum = graph->vertexNum; int count = 0; Vertex* temp; char *topSort = (char*)malloc(sizeof(char)*vexnum); int *tempindegree = (int*)malloc(sizeof(int)*vexnum); for(i = 0; i < vexnum; i++) tempindegree[i] = graph->indegree[i]; while(count < vexnum) { for(i = 0; i < vexnum; i++) { if(tempindegree[i] == 0) break; } if(i != vexnum) { tempindegree[i] = -1; //遍历后,把它排除在外 temp = &(graph->vArray[i]); topSort[count] = temp->key; while(temp->next != NULL) { temp = temp->next; GraphVertexSearch(temp->key,location); tempindegree[location]--; } } else { cout<<"The Graphic contains circle!!"<<endl; return; } count++; } cout<<"The TOPSORT result : "; for(i = 0;i < vexnum;i++) cout<<topSort[i]<<" "; cout<<endl; } int main() { MyGraph *mygraph = new MyGraph(); char edge[][2] = {{'U','V'},{'U','X'},{'V','Y'},{'Y','X'},{'X','V'},{'W','Y'},{'W','Z'}}; char vertexs[] = {'U','V','W','X','Y','Z'}; mygraph->GraphInit(edge,7,vertexs,6); cout<<"The Out-Degree of U is "<<mygraph->GraphOutDegree('U')<<endl; cout<<"The In-Degree of U is "<<mygraph->GraphInDegree('U')<<endl; mygraph->GraphBFS(); mygraph->GraphDFS(); mygraph->GraphDFSRecur(); mygraph->GraphTopSort(); return 0; }
相关文章推荐
- 广度优先遍历,深度优先遍历,拓扑排序(十字链表存储结构)
- 二叉树基本操作的递归实现(二叉树建立,先序,中序,后序,深度的递归遍历。广度优先,高度优先的非递归遍历)
- 基于邻接链表的图的广度优先搜索Java实现
- [算法] 基本图算法:深度优先搜索、广度优先搜索
- 数据结构图的基本操作--邻接表法(不包括深度、广度算法)
- 链表版本图的深度优先和广度优先遍历
- 【Python排序搜索基本算法】之深度优先搜索、广度优先搜索、拓扑排序、强联通&Kosaraju算法
- 检验深度优先和广度优先的程序(邻接矩阵存储结构)
- [置顶] 图:图的邻接矩阵创建、深度优先遍历和广度优先遍历详解
- 对邻接链表的深度优先(DFS)遍历
- 图的广度与深度搜索(邻接链表)
- 算法——基本的图算法:广度优先搜索、深度优先搜索
- 图基本算法 图搜索基于邻接表的(广度优先、深度优先)
- 图的基本操作:图的创造(基于邻接矩阵)、深度搜索(DFS)、广度搜索(DFS)
- 无向图的深度优先遍历和广度优先遍历(邻接链表)
- 二叉树的建立(非递归建立与定义建立)与基本操作(广度和深度遍历,求叶子树高)实现
- 邻接图的深度广度优先遍历
- 图的邻接矩阵存储:深度、广度优先遍历
- 图基本算法介绍:广度优先搜索、深度优先搜索、拓扑排序、强连通分支(算法篇)
- 深度优先搜索--以及图的基本操作