和树的遍历相似,若从图中某顶点出发访遍图中每个顶点,且每个顶点仅访问一次,此过程称为图的遍历(Traversing Graph)。图的遍历算法是求解图的连通性问题、拓扑排序和求关键路径等算法的基础。图的遍历顺序有两种:深度优先搜索(DFS)和广度优先搜索(BFS)。对每种搜索顺序,访问各顶点的顺序也不是唯一的。
1、邻接表及逆邻接表的存储方法
(1)定义
邻接表是图的一种链式存储结构。类似于树的孩子链表表示法。在邻接表中为图中每个顶点建立一个单链表,用单链表中的一个结点表示依附于该顶点的一条边(或表示以该顶点为弧尾的一条弧),称为边(或弧)结点。特征如下:
1)
2)
把同一个顶点发出的边链接在同一个边链表中,链表的每一个结点代表一条边,叫做表结点(边结点),邻接点域adjvex保存与该边相关联的另一顶点的顶点下标
1、广度优先遍历的递归定义
2、广度优先搜索过程
1.深度优先遍历的递归定义
假设给定图G的初态是所有顶点均未曾访问过。在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。
图的深度优先遍历类似于树的前序遍历。采用的搜索方法的特点是尽可能先对纵深方向进行搜索。这种搜索方法称为深度优先搜索(Depth-First Search)。相应地,用此方法遍历图就很自然地称之为图的深度优先遍历
2.基本实现思想:
(1)访问顶点v;
(2)从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;
(3)重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。
3、拓扑排序是对有向无环图的一种排序。表示了顶点按边的方向出现的先后顺序。如果有环,则无法表示两个顶点的先后顺序。
#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;
}