一、图的主要存储方式主要有两种:
1.邻接表表示;
2.数组表示;
其中邻接表适用于稀疏图,数组表示法适用于稠密图。由邻接表表示延伸开的还有十字链表法等。本文利用邻接表表示图,实现图的存储与遍历。
二、邻接表
邻接表分为两个部分,一部分为顶点表,可用数组表示,另一部分为边表,利用链表表示。在邻接表中,对图中的每个顶点建立一个单链表,第i个单链表中的结点表示依附于vi的边。顶点结点有两部分组成:一是存储顶点vi的名或其他信息的数据域,另一个是指向链表中第一个结点的链域;边表结点的组成为三部分,一是邻接点域(adjvex)指示与顶点vi邻接的点在图中的位置,链域(nextarc)指示下一条边或弧的结点;数据域存储与边或弧有关的信息。具体结构图如下:
边表结点 顶点表结点
三、图的遍历
1.深度优先搜索(DFS):顾名思义就是从图中某个顶点v出发,访问此顶点,然后依次从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v路径相通的顶点都被访问到;若此时尚有顶点未被访问,则另选图中一个未曾被访问的顶点做起始点,重复上述过程,直至图中所有顶点均被访问过。
2.广度优先搜索(BFS):从图中某个顶点出发,在访问了v之后,依次访问v的各个未曾被访问过的邻接点,然后分别从这些邻接点出发依次访问它们它们的邻接点,并使“先被访问过的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直至图中所有已被访问的顶点的邻接点都被访问到。若此时尚有顶点未被访问,则另选图中一个未曾被访问的顶点做起始点,重复上述过程,直至图中所有顶点均被访问过。
#ifndef DefinitionOfGraph_H
#define DefinitionOfGraph_H
#include <iostream>
#include <queue>
using namespace std;
//*****************邻接表的定义******************
//************************************************
#define MAX_VERTEX_NUM 20
typedef struct ArcNode {
int adjvex;
struct ArcNode *nextarc;
}ArcNode;
typedef struct VNode{
char data;
ArcNode *firstarc;
}VNode,AdjList[MAX_VERTEX_NUM];
typedef struct{
AdjList vertices;
int vexnum,arcnum;
int kind;
}ALGraph;
bool visited1[MAX_VERTEX_NUM ];
bool visited2[MAX_VERTEX_NUM];
//***********图的操作函数原型****************
//********************************************
void CreatGraph(ALGraph *G);//邻接表存储图
void DFS(ALGraph G,int v);
void DFSTraverse(ALGraph G);
void VisitFun(ALGraph G,int v);
void BFS(ALGraph G,int v);
void BFSTraverse(ALGraph G);
//***********图的函数操作定义****************
//********************************************
void CreatGraph(ALGraph *G)
{
int vi,vj;
ArcNode *s;
cout<<"请输入图的顶点个数:";
cin>>G->vexnum;
cout<<endl;
cout<<"请输入图的边的个数:";
cin>>G->arcnum;
cout<<endl;
cout<<"请输入顶点信息(顶点编号):"<<endl;
for(int i=0;i<G->vexnum;i++)
{//建立顶点表
cin>>G->vertices[i].data;//读入顶点信息
G->vertices[i].firstarc=NULL;//使顶点结点的指针域指向空指针域
}
cout<<"顶点表已建好!"<<endl;
for(int k=0;k<G->arcnum;k++)
{
cout<<"请输入边的信息(输入格式为:<vi,vj>):"<<endl;
cin>>vi>>vj;//vi,vj是边<vi,vj>的两个结点
s=new ArcNode;
s->adjvex=vj;//邻接点序号为vj;
s->nextarc=G->vertices[vi].firstarc;//将新的边表结点s插入到顶点vi的边表头部,这是逆序建立边表结点
G->vertices[vi].firstarc=s;
s=new ArcNode;
s->adjvex=vi;
s->nextarc=G->vertices[vj].firstarc;
G->vertices[vj].firstarc=s;
}
}
void VisitFun(ALGraph G,int v)
{
cout<<"本次访问的顶点为:"<<G.vertices[v].data<<endl;
}
void DFSTraverse(ALGraph G)
{
for(int i=0;i<G.vexnum;i++)
visited1[i]=false;
for(int i=0;i<G.vexnum;i++)
{
if(!visited1[i])
DFS(G,i);
}
}
void DFS(ALGraph G,int v)
{
//从第v个顶点开始遍历
visited1[v]=true;
VisitFun(G,v);
ArcNode *p;
p=G.vertices[v].firstarc;
while(p)
{
if(!visited1[p->adjvex])
DFS(G,p->adjvex);
p=p->nextarc;
}
}
void BFS(ALGraph G,int v)
{
queue<int>Q;
ArcNode *p;
cout<<"本次访问的顶点为:"<<G.vertices[v].data<<endl;
visited2[v]=true;
Q.push(v);
while(!Q.empty())
{
int k;
k=Q.front();
Q.pop();
p=G.vertices[k].firstarc;
while(p)
{
if(!visited2[p->adjvex])
{
cout<<"本次访问的顶点为:"<<G.vertices[p->adjvex].data<<endl;
visited2[p->adjvex]=true;
Q.push(p->adjvex);
}
p=p->nextarc;
}
}
}
void BFSTraverse(ALGraph G)
{
for(int i=0;i<G.vexnum;i++)
visited2[MAX_VERTEX_NUM]=false;
for(int i=0;i<G.vexnum;i++)
{
if(!visited2[i])
{
BFS(G,i);
}
}
}
#endif
测试:
注意:这是逆序建立边表!
如有错误,欢迎各位大神指正!