图的邻接矩阵存储结构是一个很容易理解的存储结构,用一个矩阵记录两个顶点之间的关系,对于无向无权图,用0和1来表示两个顶点之间是否相邻即可,对于无向有权图,使用一个整型来表示两个顶点之间的弧的权值即可。
存储结构的定义:
typedef char VertexType ; // 顶点类型
typedef int EdgeType ; // 边类型
#define MaxVex 100 // 最大结点数
#define INFINITY 65535
#define MaxNum 100 // 队列最大元素
// 图的邻接矩阵定义
typedef struct
{
VertexType vexs[MaxVex] ; // 顶点表
EdgeType arc[MaxVex][MaxVex] ; // 邻接边表
int numVertexes ; // 顶点数
int numEdges ; // 边数
} MGraph ;
因为这个存储结构比较简单,所以可以直接看代码就比较易懂了。
///////////////////////////////////////////////////
//
// 图的邻接矩阵的实现
//
///////////////////////////////////////////////////
////////
#include <stdio.h>
#include <stdlib.h>
typedef char VertexType ; // 顶点类型
typedef int EdgeType ; // 边类型
#define MaxVex 100 // 最大结点数
#define INFINITY 65535
#define MaxNum 100 // 队列最大元素
// 图的邻接矩阵定义
typedef struct
{
VertexType vexs[MaxVex] ; // 顶点表
EdgeType arc[MaxVex][MaxVex] ; // 邻接边
int numVertexes ; // 顶点数
int numEdges ; // 边数
} MGraph ;
typedef struct Queue // 队列的定义
{
int data[100] ;
int front ;
int rear ;
} Queue ;
typedef struct Stack
{
int data[100] ;
int top ;
int base ;
} Stack ;
bool visited[MaxVex] ; // 针对于图的递归遍历
// 队列初始化
void InitQueue( Queue * Q )
{
Q->front = 0 ;
Q->rear = 0 ;
}
// 栈的初始化
void InitStack( Stack * S )
{
S->base = 0 ;
S->top = 0 ;
}
// 队列为空
bool is_empty( Queue * Q )
{
if( Q->front == Q->rear )
{
return true ;
}
return false ;
}
// 队列已满
bool is_full( Queue * Q )
{
if( ( Q->rear + 1 ) % MaxNum == Q->front )
{
return true ;
}
return false ;
}
// 判断栈为空
bool is_stack_empty( Stack * S )
{
if( S->base == S->top )
{
return true ;
}
return false ;
}
// 判断栈已满
bool is_stack_full( Stack * S )
{
if( S->top - S->base + 1 == MaxNum )
{
return true ;
}
return false ;
}
// 入队
void EnQueue( Queue * Q , int elem )
{
if( !is_full( Q ) )
{
Q->data[Q->rear] = elem ;
Q->rear = ( Q->rear + 1 ) % MaxNum ;
}
}
// 出队
void DeQueue( Queue * Q , int * elem )
{
if( !is_empty( Q ) )
{
*elem = Q->data[Q->front++] ;
}
}
// 入栈
void Push( Stack * S , int elem )
{
if( !is_stack_full( S ) )
{
S->data[S->top++] = elem ;
}
}
// 出栈
void Pop( Stack * S , int * elem )
{
if( !is_stack_empty( S ) )
{
*elem = S->data[--S->top] ;
}
}
// 初始化图
void InitGraph( MGraph * G )
{
G->numEdges = 0 ;
G->numVertexes = 0 ;
}
// 创建图
void CreateGraph( MGraph * G )
{
/*
printf("请输入顶点的数目:") ;
scanf("%d", &G->numVertexes ) ;
printf("请输入边的数目:") ;
scanf("%d" , &G->numEdges ) ;
printf("请输入顶点域的内容:") ;
for( int i = 0 ; i < G->numVertexes ; i++ )
{
scanf("%c" ,&G->vexs[i] ) ;
}
printf("请输入各顶点之间边的关系:\n") ;
for( i = 0 ; i < G->numVertexes ; i++ )
{
for( int j = 0 ; j < G->numVertexes ; j++ )
{
scanf("%d" , &G->arc[i][j] ) ;
}
}
*/
G->numVertexes = 6 ;
G->numEdges = 7 ;
G->vexs[0] = 'A' ;
G->vexs[1] = 'B' ;
G->vexs[2] = 'C' ;
G->vexs[3] = 'D' ;
G->vexs[4] = 'E' ;
G->vexs[5] = 'F' ;
G->arc[0][0] = 0 ;
G->arc[0][1] = 1 ;
G->arc[0][2] = 1 ;
G->arc[0][3] = 0 ;
G->arc[0][4] = 0 ;
G->arc[0][5] = 1 ;
G->arc[1][0] = 1 ;
G->arc[1][1] = 0 ;
G->arc[1][2] = 1 ;
G->arc[1][3] = 0 ;
G->arc[1][4] = 1 ;
G->arc[1][5] = 0 ;
G->arc[2][0] = 1 ;
G->arc[2][1] = 1 ;
G->arc[2][2] = 0 ;
G->arc[2][3] = 1 ;
G->arc[2][4] = 0 ;
G->arc[2][5] = 0 ;
G->arc[3][0] = 0 ;
G->arc[3][1] = 0 ;
G->arc[3][2] = 1 ;
G->arc[3][3] = 0 ;
G->arc[3][4] = 1 ;
G->arc[3][5] = 0 ;
G->arc[4][0] = 0 ;
G->arc[4][1] = 1 ;
G->arc[4][2] = 0 ;
G->arc[4][3] = 1 ;
G->arc[4][4] = 0 ;
G->arc[4][5] = 0 ;
G->arc[5][0] = 1 ;
G->arc[5][1] = 0 ;
G->arc[5][2] = 0 ;
G->arc[5][3] = 0 ;
G->arc[5][4] = 0 ;
G->arc[5][5] = 0 ;
}
// 邻接矩阵的广度优先遍历算法
void BFS( MGraph * G )
{
bool visited[MaxVex] ; // 表示该顶点是否被访问过
int i , j ;
Queue Q ;
for( i = 0 ; i < G->numVertexes ; i++ ) // 初始化
{
visited[i] = false ; // 最开始所有顶点都未被访问
}
InitQueue( &Q ) ; // 初始化队列
for( i = 0 ; i < G->numVertexes ; i++ )
{
if( !visited[i] )
{
EnQueue( &Q , i ) ; // 入队
printf("%c " , G->vexs[i] ) ; // 访问该顶点
visited[i] = true ; // 标记为已访问
while( !is_empty( &Q ) )
{
DeQueue( &Q , &i ) ; // 出队,并将出队的元素返回到变量i中
for( j = 0 ; j < G->numVertexes ; j++ ) // 遍历与顶点i相邻的顶点
{
if( G->arc[i][j] == 1 && visited[j] == false )
{
EnQueue( &Q , j ) ; // 与顶点i相邻的顶点j入队
printf("%c " , G->vexs[j] ) ; // 访问该顶点
visited[j] = true ;
}
}
}
}
}
}
// 邻接矩阵的深度优先遍历 非递归实现
void DFS( MGraph * G )
{
int i = 0 ;
int j = 0 ;
int k = 0 ;
bool visited[MaxVex] ;
Stack S ;
InitStack( &S ) ; // 初始化栈
for( i = 0 ; i < G->numVertexes ; i++ )
{
visited[i] = false ; // 初始化为未访问
}
for( i = 0 ; i < G->numVertexes ; i++ ) // 这个循环主要是针对非连通图,若是连通图则可以省去这个顶点
{
if( visited[i] == false ) // 未访问
{
Push( &S , i ) ;
while( !is_stack_empty( &S ) )
{
Pop( &S , &i ) ;
if( visited[i] == false )
{
printf("%c " , G->vexs[i] ) ; // 访问该顶点
visited[i] = true ; // 标记为已访问
}
for( j = 0 ; j < G->numVertexes ; j++ ) // 遍历与当前顶点相邻的顶点
{
if( G->arc[i][j] == 1 && visited[j] == false )
{
Push( &S , j ) ;
}
}
}
}
}
}
// 初始化全局变量visited[MaxVex]
void InitVisit( MGraph * G , bool * visited )
{
for( int i = 0 ; i < G->numVertexes ; i++ )
{
visited[i] = false ;
}
}
// 存储结构为邻接矩阵的图的遍历的递归实现
void DFS_Recursion( MGraph * G , int v )
{
if( visited[v] == false )
{
printf("%c " , G->vexs[v] ) ;
visited[v] = true ;
}
for( int k = 0 ; k < G->numVertexes ; k++ )
{
if( G->arc[v][k] == 1 && visited[k] == false )
{
DFS_Recursion( G , k ) ;
}
}
}
void DFS_Traverse_Recursion( MGraph * G )
{
for( int i = 0 ; i < G->numVertexes ; i++ )
{
DFS_Recursion( G , i ) ;
}
}
// 测试
int main()
{
MGraph G ;
InitGraph( &G ) ; // 初始化图
CreateGraph( &G ) ; // 创建图
BFS( &G ) ; // 宽度优先遍历图
printf("\n") ;
DFS( &G ) ; // 广度优先遍历
printf("\n") ;
InitVisit( &G , visited ) ;
DFS_Traverse_Recursion( &G ) ;
printf("\n") ;
return 0 ;
}