由于图的复杂结构,其物理位置与逻辑位置并不匹配,不能用一维数组来存储图。可考虑用一维数组来存储图的结点信息,二维数组来存储节点间的关系,这种存储方式就叫做邻接矩阵。
图的结点结构定义:
typedef struct
{
char vexs[ MVNum ] ;//存储结点信息
int arcs[ MVNum ][ MVNum ] ; //存储权值
int vexnum , arcnum ;//定义图的节点个数和边的条数
}AMGraph ;
查找结点元素在vexs[]数组中的下标:
int LocateVex( AMGraph G , char ch )
{
int i ;
for( i = 0 ; i < G.vexnum ; i++ )
if( ch == G.vexs[ i ] )
break ;
return i ;
}
创建图:
在创建图的过程中,如果结点信息是字符,且用scanf()函数从键盘读取的话,一定要用getchar()将键盘输入后的回车键吸收。这是因为当用户按下回车键时,回车符还在缓冲区内,当下一次调用scanf()时,程序会读取缓冲区内遗留的回车符。关于scanf()的更加详细的解释:C语言scanf函数用法详细解释!
Status CreateUDN( AMGraph *G )
{
int i , j ;
printf( "请输入结点个数:" ) ;
scanf( "%d" , &G->vexnum ) ;
getchar() ;
for( i = 0 ; i < G->vexnum ; i++ )
{
printf( "请输入第%d个结点的信息:" , i+1 ) ;
scanf( "%c" , &G->vexs[ i ] ) ;
getchar() ;
}
for( i = 0 ; i < G->vexnum ; i++ )
for( j = 0 ; j < G->vexnum ; j++ )
G->arcs[ i ][ j ] = MaxInt ;
printf( "请输入边的条数:" ) ;
scanf( "%d" , &G->arcnum ) ;
getchar() ;
for( i = 0 ; i < G->arcnum ; i++ )
{
int w ;
char a , b ;
printf( "请输入两个结点以及两节点间的边的权值:" ) ;
scanf( "%c %c %d" , &a , &b , &w ) ;
getchar() ;
G->arcs[ LocateVex( *G , a ) ][ LocateVex( *G , b ) ] = w ;
G->arcs[ LocateVex( *G , b ) ][ LocateVex( *G , a ) ] = w ;
}
return OK ;
}
邻接矩阵实现DFS算法:
DFS就相当于树的前序遍历。
用visited[]数组来标志结点是否已被遍历过。
void DFS( AMGraph G , int i )
{
int j ;
visited[ i ] = TRUE ;
printf( "%c " , G.vexs[ i ] ) ;
for( j = 0 ; j < G.vexnum ; j++ )
if( !visited[ j ] && G.arcs[ i ][ j ] < MaxInt && G.arcs[ i ][ j ] > 0 )
DFS( G , j ) ;
}
void DFSTraverse( AMGraph G )
{
int i ;
for( i = 0 ; i < G.vexnum ; i++ )
visited[ i ] = FALSE ;
for( i = 0 ; i < G.arcnum ; i++ )
if( !visited[ i ] )
DFS( G , i ) ;
}
这里对每个结点都实现DFS可以避免不能遍历非连通图的情况。
邻接矩阵实现BFS算法:
BFS算法需借助于队列来实现,其基本思想是:遍历第一个结点,并将其入队之后,再把它出队,然后把与这个结点相连的所有结点都入队,每遍历一次都进行这样的操作,BFS就相当于树的层序遍历。
void BFSTraverse( AMGraph G )
{
char temp ;
int i , j ;
Queue Q ;
InitQueue( &Q ) ;
for( i = 0 ; i < G.vexnum ; i++ )
visited[ i ] = FALSE ;
for( i = 0 ; i < G.vexnum ; i++ )
{
if( !visited [ i ] )
{
visited[ i ] = TRUE ;
printf( "%c " , G.vexs[ i ] ) ;
EnQueue( &Q , G.vexs[ i ] ) ;
while( !EmptyQueue( Q ) )
{
DeQueue( &Q , &temp ) ;
for( j = 0 ; j < G.vexnum ; j++ )//将与刚刚遍历过的结点相连的结点都入队
{
if( G.arcs[ i ][ j ] < MaxInt && G.arcs[ i ][ j ] > 0 && !visited[ j ] )
{
visited[ j ] = TRUE ;
printf( "%c " , G.vexs[ j ] ) ;
EnQueue( &Q , G.vexs[ j ] ) ;
}
}
}
}
}
printf( "\n" ) ;
}
判断队列已满和入队与出队的操作比较简单,这里就不一一列出。
附上源代码:
#include<stdio.h>
#include<stdlib.h>
#define MVNum 100
#define MaxInt 32767
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef char VerTexType ;
typedef int ArcType ;
typedef int Status ;
typedef int Boolean ;
typedef struct
{
VerTexType vexs[ MVNum ] ;
ArcType arcs[ MVNum ][ MVNum ] ;
int vexnum , arcnum ;
}AMGraph ;
typedef struct
{
char *base ;
int front ;
int rear ;
}Queue ;
Boolean visited[ MaxInt ] ;
Status CreateUDN( AMGraph *G ) ;
void DFS( AMGraph G , int i ) ;
void DFSTraverse( AMGraph G ) ;
int LocateVex( AMGraph G , char ch ) ;
void InitQueue( Queue *Q ) ;
int EmptyQueue( Queue Q ) ;
int EnQueue( Queue *Q , char ch ) ;
int DeQueue( Queue *Q , char *ch ) ;
void BFSTraverse( AMGraph G ) ;
int main( void )
{
AMGraph G ;
CreateUDN( &G ) ;
DFSTraverse( G ) ;
BFSTraverse( G ) ;
return 0 ;
}
int LocateVex( AMGraph G , char ch )
{
int i ;
for( i = 0 ; i < G.vexnum ; i++ )
if( ch == G.vexs[ i ] )
break ;
return i ;
}
Status CreateUDN( AMGraph *G )
{
int i , j ;
printf( "请输入结点个数:" ) ;
scanf( "%d" , &G->vexnum ) ;
getchar() ;
for( i = 0 ; i < G->vexnum ; i++ )
{
printf( "请输入第%d个结点的信息:" , i+1 ) ;
scanf( "%c" , &G->vexs[ i ] ) ;
getchar() ;
}
for( i = 0 ; i < G->vexnum ; i++ )
for( j = 0 ; j < G->vexnum ; j++ )
G->arcs[ i ][ j ] = MaxInt ;
printf( "请输入边的条数:" ) ;
scanf( "%d" , &G->arcnum ) ;
getchar() ;
for( i = 0 ; i < G->arcnum ; i++ )
{
int w ;
char a , b ;
printf( "请输入两个结点以及两节点间的边的权值:" ) ;
scanf( "%c %c %d" , &a , &b , &w ) ;
getchar() ;
G->arcs[ LocateVex( *G , a ) ][ LocateVex( *G , b ) ] = w ;
G->arcs[ LocateVex( *G , b ) ][ LocateVex( *G , a ) ] = w ;
}
return OK ;
}
void DFS( AMGraph G , int i )
{
int j ;
visited[ i ] = TRUE ;
printf( "%c " , G.vexs[ i ] ) ;
for( j = 0 ; j < G.vexnum ; j++ )
if( !visited[ j ] && G.arcs[ i ][ j ] < MaxInt && G.arcs[ i ][ j ] > 0 )
DFS( G , j ) ;
}
void DFSTraverse( AMGraph G )
{
int i ;
for( i = 0 ; i < G.vexnum ; i++ )
visited[ i ] = FALSE ;
for( i = 0 ; i < G.arcnum ; i++ )
if( !visited[ i ] )
DFS( G , i ) ;
printf( "\n" ) ;
}
void InitQueue( Queue *Q )
{
Q->base = ( char * )malloc( sizeof( char ) * MaxInt ) ;
Q->front = Q->rear = 0 ;
}
int EmptyQueue( Queue Q )
{
if( Q.front == Q.rear )
return TRUE ;
else
return FALSE ;
}
int EnQueue( Queue *Q , char ch )
{
if( ( Q->rear + 1 ) % MaxInt == Q->front )
return ERROR ;
else
{
Q->base[ Q->rear ] = ch ;
Q->rear = ( Q->rear +1 ) % MaxInt ;
}
return OK ;
}
int DeQueue( Queue *Q , char *ch )
{
if( EmptyQueue( *Q ) )
return ERROR ;
else
{
*ch = Q->base[ Q->front ] ;
Q->front = ( Q->front + 1 ) % MaxInt ;
}
return OK ;
}
void BFSTraverse( AMGraph G )
{
char temp ;
int i , j ;
Queue Q ;
InitQueue( &Q ) ;
for( i = 0 ; i < G.vexnum ; i++ )
visited[ i ] = FALSE ;
for( i = 0 ; i < G.vexnum ; i++ )
{
if( !visited [ i ] )
{
visited[ i ] = TRUE ;
printf( "%c " , G.vexs[ i ] ) ;
EnQueue( &Q , G.vexs[ i ] ) ;
while( !EmptyQueue( Q ) )
{
DeQueue( &Q , &temp ) ;
for( j = 0 ; j < G.vexnum ; j++ )
{
if( G.arcs[ i ][ j ] < MaxInt && G.arcs[ i ][ j ] > 0 && !visited[ j ] )
{
visited[ j ] = TRUE ;
printf( "%c " , G.vexs[ j ] ) ;
EnQueue( &Q , G.vexs[ j ] ) ;
}
}
}
}
}
printf( "\n" ) ;
}