图的基本概率:
-
点集 V(vertexs)和边集 E(edges)组成
-
有向图和无向图
-
弧 Arc : <vi ,vj>
-
路径: 相邻顶点序偶构成的序列
-
路径长度: 路径上边的数目
图的存储结构:
-
邻接矩阵(顺序存储结构,无向图是对称的)
-
邻接表(链式存储结构)
代码实现:
1: 邻接矩阵 (DFS ,BFS遍历)
2: 邻接表 ( DFS ,BFS遍历)
1: 邻接矩阵(DFS ,BFS遍历)
/*
编制日期:2020-5-20
图的存储:邻接矩阵
图的遍历:1:DFS 2:BFS
*/
#include <iostream>
#include<cstring>
using namespace std ;
#define MaxSize 50 //图最大顶点个数
#define inf 999999999 //无穷大值,在图中表示不连通
typedef int datatype; //可以根据需要改变数据类型,也可以自己封装数据类型
//邻接矩阵
typedef struct{
int num; //顶点编号
char info; //顶点信息
}Node ; // 顶点类型
typedef struct{
datatype edgs[MaxSize][MaxSize] ; //保存图的,边集权重信息
int n,e ; // n 顶点的总数, e 边数
Node nodes[MaxSize] ; //保存顶点信息
}MGraph;
int visited[MaxSize] ; //访问记录数组
/* 构造图的初始函数 */
MGraph InitiaL_Graph(){
MGraph graph ;
int n ,e ;
int i, j ;
cout<<"初始化图操作:请输入你要构造的图的 顶点数(n) 和边数(e)"<<endl ;
cout<<"请输入n: \t";
cin>>n;
cout<<"请输入e:\t";
cin>>e;
graph.n = n ;
graph.e = e ;
for(i=1;i<=n;i++ ){
for(j=1;j<=n;j++){
if(i == j)
graph.edgs[i][i] = 0 ; //同一点距离为 0
else
graph.edgs[i][j] =inf ; 把每条边赋值无穷大,表示不连通
}
}
cout<<"请输入边值权重"<<endl ;
cout<<" edgs[i][j] = weight,如果没有图中没有weight,请全输入1占位: 输入格式 i ,j ,weight"<<endl ;
i= 1 ;
j=1;
while(e--){
datatype temp ;
cin>>i>>j>>temp ;
graph.edgs[i][j] = temp ;
}
return graph ;
}
/* 处理函数,根据实际需要编写 */
void process(MGraph graph , int v)
{
cout<<v<<" " ; //打印遍历结点
}
/* DFS基本思想 :
步骤1:访问出发点 V,然后标记已经访问过,然后选取V,邻接的未被访问的任意一个结点 i 访问
步骤2:对结点i ,重复步骤1
*/
void DFS(MGraph graph, int v)
{
int i ;
//步骤1
visited[v] = 1 ; //标记已经访问
process(graph,v) ; //对结点v的操作
for(i =1;i<=graph.n ;i++){
if(graph.edgs[v][i]!=inf && visited[i]==0&&graph.edgs[v][i]!=0){ //注意条件,edges[v][i]这条边必须存在,和结点i没有被访问过,visited[i] =0
//步骤2
visited[i] =1 ; //i 结点表示访问
DFS(graph,i); //继续向前搜索
}
}
}
/* BFS基本思想:
步骤1:访问初始点v ,接着访问与v结点邻接的所有结点 j1,j2,....jn
步骤2:然后接着,依次访问j1,j2,....jn 邻接的所有结点(访问的结点除外)
算法实现借助队列
*/
void BFS(MGraph graph ,int v)
{
int Queue[MaxSize] ,Front=0,Rear = 0 ;
int i ;
//步骤1
visited[v] = 1 ;
process(graph,v) ; //对结点v 的操作
Rear =(Rear+1) %MaxSize ;
Queue[Rear] = v ;
//步骤2:
while(Front != Rear){
Front = (Front +1) %MaxSize ;
i = Queue[Front] ; //将当前没有访问i 结点的邻接点入队
for(int j = 1 ;j<=graph.n;j++){
if(visited[j]==0 && graph.edgs[i][j]!=inf && graph.edgs[i][j]!=0){
process(graph,j);
visited[j]=1 ;
Rear =(Rear+1)%MaxSize ;
Queue[Rear] = j ;
}
}
}
}
int main()
{
int i ;
MGraph graph = InitiaL_Graph() ;
memset(visited,0,sizeof(visited)) ; //标记数组全置为0
cout<<"图的邻接矩阵如下:"<<endl ;
for(i=1 ;i<=graph.n ;i++){
for (int j=1 ;j<=graph.n;j++)
cout<<graph.edgs[i][j]<<" ";
cout<<endl ;
}
for(i= 1 ;i<=graph.n;i++)
visited[i] = 0 ;
cout<<"图的深度优先搜索遍历: DFS"<<endl ;
for(i = 1 ; i<=graph.n ;i++){
if(visited[i]==0){
DFS(graph ,i) ;
}
}
cout<<endl ;
cout<<"图的广度优先搜索遍历: BFS"<<endl ;
memset(visited,0,sizeof(visited)) ; //标记数组全置为0
for(i= 1 ;i<=graph.n;i++)
visited[i] = 0 ;
for(i = 1 ; i<=graph.n ;i++){
if(visited[i]==0){
BFS(graph ,i) ;
}
}
cout<<endl ;
return (1) ;
}
/*
输入 n =5 ,e =5
图:
1 2 1
1 3 1
1 5 1
2 4 1
5 4 1
*/
2: 邻接表 ( DFS ,BFS遍历)
/*
编制日期: 2020-5-21
图的存储: 邻接表
图的遍历: 1:DFS 2:BFS
*/
#include <iostream>
#include<cstring>
using namespace std ;
#define MaxSize 50 //图最大顶点个数
#define inf 999999999 //无穷大值,在图中表示不连通
typedef int datatype; //可以根据需要改变数据类型,也可以自己封装数据类型
//邻接表
typedef struct ArcNode{
int adjvex; //该边指向的顶点编号,(邻接点编号)
ArcNode *next ; //指向下一条边的指针
datatype info; //边的信息,可以是权重
}ArcNode ; //一个弧结点
typedef struct{
int num ; // 顶点编号信息
ArcNode *firstArc ; // 指向第一条边的指针
}VNode ; //结点
typedef struct{
int n,e ; // n 图顶点的总数, e 边数
VNode adjList[MaxSize] ; //各节点邻接表(一个节点一条链表,链表中元素为邻接边顶点adjvex,和边上info)
}AGraph;
int visited[MaxSize] ; //访问记录数组
/* 构造图的初始函数 */
AGraph* InitiaL_Graph(){
AGraph *graph ;
int n ,e ; // n ,这个图的顶点个数,e 变数
int i;
graph = new AGraph ; //开辟一个图存储空间,不然有空指针异常
cout<<"初始化图操作: 请输入你要构造的图的 顶点数(n) 和边数(e)"<<endl ;
cout<<"请输入总的顶点数: n \t";
cin>>n;
cout<<"请输入总的变数: e: \t";
cin>>e;
graph->n = n ;
graph->e = e ;
cout<<"请输入各个顶点的邻接边:\tadjvex: 顶点编号\t weight: 边值权重,没有输入1占位 "<<endl ;
i =1 ;
while(i<=n){
VNode *vnodei ; //节点邻接链
ArcNode *arcNodeHead,*temp_arnode; //节点链表,采用尾插法,temp_arcnode ,是临时结点,arcNodeHead是链表头
vnodei = new VNode ; //分配地址,不然有空指针异常
arcNodeHead = new ArcNode;
arcNodeHead->next =NULL; //初始化链表
arcNodeHead->adjvex=i ; //第一个邻接点,指向自己,这条语句可以不要
temp_arnode = arcNodeHead ;
while(true){
int node_num ; //邻结点编号
datatype nodeWeight ; //邻结点这条边的(info) 测试采用的权重
ArcNode *temp; //临时保存一条邻接边的信息
cout<<"第"<<i<<"个结点的邻接链表,格式:邻结点的: 编号 权重(没有输入1占位), 输入 -1 0 结束"<<endl ;
cin>>node_num>>nodeWeight ;
if(node_num==-1){
temp_arnode->next =NULL ;
break ;
}
temp = new ArcNode ;
temp->adjvex = node_num ;
temp->info = nodeWeight ;
temp_arnode->next = temp ; //将邻接边加入链表中,尾插法
temp_arnode = temp ; //指针后移动
}
temp_arnode->next=NULL ; //链表尾置为空
vnodei->firstArc =arcNodeHead->next ; //应为第一个结点没有保存领接边信息,后移1位
vnodei->num = i ; //标记为i结的邻接边
graph->adjList[i] = *vnodei; //添加到图的邻接表中
i++ ; //下一个结点
}
return graph ;
}
/* 处理函数,根据实际需要编写 */
void process(AGraph *graph , int v)
{
cout<<v<<" " ; //打印遍历结点
}
/* DFS基本思想 :
步骤1: 访问出发点 V,然后标记已经访问过,然后选取V,邻接的未被访问的任意一个结点 i 访问
步骤2: 对结点i ,重复步骤1
*/
void DFS(AGraph *graph,int v)
{
ArcNode *p ;
//步骤1
visited[v] =1 ;
process(graph ,v) ;
p = graph->adjList[v].firstArc ; //结点v的邻接边链
//步骤2
while(p!=NULL){
if(visited[p->adjvex]==0){
DFS(graph,p->adjvex); //继续向前搜索
}
p=p->next ; //下一个邻接点
}
}
void PrintAdj(AGraph *graph)
{
int i,n,num ;
n = graph->n ; //图的变数
for(i=1;i<=n;i++){
ArcNode *p ;
num = graph->adjList[i].num ; //结点i编号
p= graph->adjList[i].firstArc ; //结点i的邻结点链
cout<<num<<" ->";
while(p){
cout<<p->adjvex<<"->" ; //邻结点编号
p=p->next ;
}
cout<<endl ;
}
}
/* BFS基本思想:
步骤1: 访问初始点v ,接着访问与v结点邻接的所有结点 j1,j2,....jn
步骤2: 然后接着,依次访问j1,j2,....jn 邻接的所有结点(访问的结点除外)
算法实现借助队列
*/
void BFS(AGraph *graph , int v)
{
ArcNode *p ;
int Queue[MaxSize] ,Front=0 ,Rear=0 ;
int i ;
//步骤1
process(graph ,v); //对结点v 的操作
visited[v] = 1 ; //标记结点v访问
Rear =(Rear + 1)%MaxSize ;
Queue[Rear] = v ; //结点v进队
//步骤2
while(Rear != Front){
Front =(Front +1 )%MaxSize ;
i = Queue[Front] ;
p = graph->adjList[i].firstArc ; //第一个邻结点
while(p!=NULL){
if(visited[p->adjvex]==0){ //邻接点没被访问
process(graph,p->adjvex) ; //对邻结点操作
visited[p->adjvex] =1 ; //标记这个结点访问
Rear = (Rear+1)%MaxSize ; //进队
Queue[Rear] = p->adjvex ;
}
p= p->next ; //下一个邻结点
}
}
}
int main()
{
int i ,n ;
AGraph *graph = InitiaL_Graph() ; //图的初始化
//打印图的邻接表
cout<<"邻接表"<<endl ;
PrintAdj(graph);
n = graph->n ; //图的表数
memset(visited,0,sizeof(visited)) ; //清0
for(i=1;i<=n;i++)
visited[i] =0 ; // 0 表示未被访问 1表示访问
cout<<"深度优先搜索遍历"<<endl ;
for(int i=1;i<=graph->n;i++){
if(visited[i]==0)
DFS(graph,i) ;
}
cout<<endl ;
memset(visited,0,sizeof(visited)) ;
for(i=1;i<=n;i++)
visited[i] =0 ;
cout<<"广度优先搜索遍历"<<endl ;
for(int i=1;i<=graph->n;i++){
if(visited[i]==0)
BFS(graph,i) ;
}
return (1) ;
}
/*
输入 n = 5 e= 7
i=1 :
2 1
4 1
5 1
-1 0
i=2 :
5 1
3 1
-1 0
i=3:
1 1
-1 0
i=4:
3 1
-1 0
i=5:
-1 0
end
*/