第七章(2).图的邻接表存储表示
来源:互联网 发布:淘宝500的充气娃娃图片 编辑:程序博客网 时间:2024/06/05 05:18
//邻接表中,对图中每个顶点建立一个单链表,第i个单链表中的节点表示依附于顶点vi的边(对有向图是以顶点vi为尾的弧)
//每个链表中的节点有三个域组成:邻接点域(adjvex),链域(nextarc),数据域(info)
//每个链表附设一个表头节点。表头节点只有链域(firstarc)和数据域(data)
#include < stdio.h >
#include < stdlib.h >
#include < string.h >
#include < limits.h >#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2typedef int Status ;
//-------------------------图的邻接表存储表示-------------------------------//
//#define INFINITY INT_MAX //最大值(无穷大)INT_MAX = 2147483647
#define MAX_VERTEX_NUM 20 //最大顶点个数(vertex顶点)
//#define MAX_INFO 20 //关于边的信息的字符串长度
#define MAX_NAME 5 //关于顶点信息的字符串长度typedef int VRType ; //此处考虑无权图
typedef int InfoType ; //如果为字符信息,则可以用char;如果为权值,则可以用int.
//typedef char* VertexType ;
typedef char VertexType[ MAX_NAME ]; //VertexType可以根据实际情况灵活设定类型!int,float,char…
typedef enum{ DG , DN , UDG , UDN }GrapKind ; //{有向图(Digraph),有向网(Digraph Network), 无向图(Undigraph),无向网(Undigraph Network)}typedef struct ArcNode{ //表结点
int adjvex ; //该弧所指向的顶点的位置
struct ArcNode *nextarc ; //指向下一条弧的指针
InfoType *info ; //该弧相关信息指针(如权值等)
} ArcNode ;typedef struct VNode { //表头结点
VertexType data ; //顶点信息
ArcNode *firstarc ; //指向第一条依附该顶点的弧的指针
} VNode , AdjList[ MAX_VERTEX_NUM ] ;typedef struct {
AdjList vertices ;
int vexnum , arcnum ; //图当前的顶点树和弧数
GrapKind kind ;
} ALGraph ;//----------------------------------------------------------------//
//有时,为了便于确定顶点的入度或以顶点vi为头的弧,可以建立一个有向图的逆邻接表,既对每个顶点vi建立一个链表以vi为头的弧的表(只适合有向图)
//若无向图中有n个顶点,e条边,则它的邻接表需n个头节点和2e个表结点。显然,在边稀疏(e << n(n-1)/2 )的情况下,用邻接表表示图比邻接矩阵节省存储空间
//-------------------------Link Queue---------------------------//typedef int QElemType ;
typedef struct QNode //链结点
{
QElemType data ;
struct QNode *next ;
} QNode , *QueuePtr ;typedef struct
{
QueuePtr front ; //队头指针 队头出元素
QueuePtr rear ; //队尾指针 队尾进元素
} LinkQueue ;Status InitQueue( LinkQueue *Q ) ;
Status EnQueue( LinkQueue *Q , QElemType e ) ;
Status DeQueue( LinkQueue *Q , QElemType *e ) ;
Status QueueEmpty( LinkQueue Q ) ;//-------------------------------------------------------------//
//--------------------------------------------------------------//
Status InitGraph( ALGraph *G )
{
int i ;printf( "Please input the number of vex and arc:" ) ;
scanf( "%d%d" , &( *G ).vexnum , &( *G ).arcnum ) ;printf( "Please input the kind of ALGraph(0 means DG ) :" ) ;
scanf( "%d" , &( *G ).kind ) ;printf("Input the vector of %d vex( %d char ): \n" , ( *G ).vexnum , MAX_NAME ) ;
for( i = 0 ; i < ( *G ).vexnum ; ++ i ) //构造顶点向量,同时也初始化表头结点数组。
{
scanf( "%s" , ( *G ).vertices[ i ].data ) ;
( *G ).vertices[ i ].firstarc = NULL ;
}return OK ;
}Status LocateVex( ALGraph G , VertexType u )
{
int k ;for( k = 0 ; k < G.vexnum ; ++ k )
{
if( strcmp( u , G.vertices[ k ].data ) == 0 )
return k ;
}
return EOF ;
}Status CreateGraph( ALGraph *G )
{
int i ;
int l , j ; //定位弧头弧尾
InfoType infor ; //权值信息
VertexType va , vb ;
ArcNode *p ;InitGraph( G ) ;
if( ( *G ).kind % 2 ) //网
{
printf( "Please input the weight , vexa ant vexb:" ) ; //权值,弧头,弧尾。
}
else //图
{
printf( "Please input the vexa and vexb:\n" ) ;
}//-----------------------------------------------------//
for( i = 0 ; i < ( *G ).arcnum ; ++ i )
{
if( ( *G ).kind % 2 )
{
scanf( "%d%s%s%*c" , &infor , va , vb ) ;
}
else
{
scanf( "%s%s" , va , vb ) ;
}l = LocateVex( *G , va ) ; //弧尾 va----->vb
j = LocateVex( *G , vb ) ; //弧头
p = ( ArcNode * )malloc( sizeof( ArcNode ) ) ; //adjvex
p->adjvex = j ; //Take care!if( ( *G ).kind % 2 ) //info
{
p->info = ( InfoType * )malloc( sizeof( InfoType ) ) ; //切记不可丢!为指针,要用则必须申请空间。
*( p->info ) = infor ;
}
else
p->info = NULL ;p->nextarc = ( *G ).vertices[ l ].firstarc ; //nextarc
( *G ).vertices[ l ].firstarc = p ;
if( ( *G ).kind > 1 ) //UDG and UDN
{
p = ( ArcNode * )malloc( sizeof( ArcNode ) ) ;
p->adjvex = l ;if( ( *G ).kind == 3 )
{
p->info = ( InfoType * )malloc( sizeof( InfoType ) ) ;
*( p->info ) = infor ;
}
else
p->info= NULL ;p->nextarc = ( *G ).vertices[ j ].firstarc ;
( *G ).vertices[ j ].firstarc = p ;
}
}
//---------------------------------------------------------------//
return OK ;
}Status DestroyGraph( ALGraph *G ) //释放资源和初始化
{
int i ;
ArcNode * p , * q ;
( *G ).arcnum = 0 ;
( *G ).vexnum = 0 ;for( i = 0 ; i < ( *G ).vexnum ; ++ i )
{
p = ( *G ).vertices[ i ].firstarc ;
while( p )
{
q = p->nextarc ;
if( ( *G ).kind % 2 ) //Net
free( p->info ) ;
free( p ) ;
p = q ;
}
}
return OK ;
}VertexType *GetVex( ALGraph G , int n ) //返回序号为n的顶点值
{
if( n < 0 || n >= G.vexnum )
return ERROR ;return &(G.vertices[ n ].data ) ;
}Status PutVex( ALGraph *G , VertexType u , VertexType w ) //把u赋值为w
{
int i ;
/*
for( i = 0 ; i < ( *G ).vexnum ; ++ i )
{
if( strcmp( u , ( *G ).vertices[ i ].data ) == 0 )
{
strcpy( ( *G ).vertices[ i ].data , w ) ;
return OK ;
}
}
return ERROR ;
*/
i = LocateVex( *G , u ) ; //谁更方便? 差不多?!
if( i > -1 ) //*G中存在u结点
{
strcpy( ( *G ).vertices[ i ].data , w ) ;
return OK ;
}
return ERROR ;
}//------------------------------------------------------------------------//
//在邻接表上容易找到任一顶点的第一个邻接点和下一个邻接点,但是要判断任意两个
//顶点之间是否有边或弧相连,则需要搜索第i个和第j链表,因此不及邻接矩阵方便Status FirstAdjVex( ALGraph G , VertexType u ) //返回第一个邻接点以及其序号
{
int k ;
ArcNode *p ;k = LocateVex( G , u ) ;
if( k < 0 )
return EOF ; //不能return ERROR ; 因为ERROR = 0 ;p = G.vertices[ k ].firstarc ;
if( p )
{
// puts( G.vertices[ p->adjvex ].data ) ;
// return G.vertices[ k ].firstarc->adjvex ;
return p->adjvex ;
}
else
return EOF ;
}Status NextAdjVex( ALGraph G , VertexType u , VertexType w ) //返回G中u相对于w的下一个邻接点
{
int k , l ;
ArcNode *p ;k = LocateVex( G , u ) ;
l = LocateVex( G , w ) ;if( k < 0 || l < 0 )
return EOF ;p = G.vertices[ k ].firstarc ;
while( p->adjvex != l && p )
{
p = p->nextarc ;
}
if( !p || !p->nextarc ) //要考虑到p->nextarc为空的情况
return EOF ;
else
{
// puts( G.vertices[ p->nextarc->adjvex ].data ) ;
return p->nextarc->adjvex ;
}
}Status InserVex( ALGraph *G , VertexType u ) //插入结点
{
// VNode *p ; //表头结点// p = ( VNode * )malloc( sizeof( VNode ) ) ; //字符串可以直接赋值,不必申请空间
// if( !p )
// exit( OVERFLOW ) ;if( ( *G ).vexnum == MAX_VERTEX_NUM ) //结点数满
return ERROR ;
if( LocateVex( *G , u ) >= 0 ) //结点已存在
return ERROR ;strcpy( ( *G ).vertices[ ( *G ).vexnum ].data , u ) ;
( *G ).vertices[ ( *G ).vexnum ].firstarc = NULL ;
++ ( *G ).vexnum ;return OK ;
}Status DeleteVex( ALGraph *G , VertexType u ) //删除结点(除了删除该结点以及该结点的弧外,还要遍历邻接表,删除含有该结点的弧)
{
int k , i ;
ArcNode *p , *q ;k = LocateVex( *G , u ) ;
if( k < 0 )
return EOF ;
p = ( *G ).vertices[ k ].firstarc ; //(1)
while( p )
{
q = p->nextarc ;if( ( *G ).kind % 2 ) //网
free( p->info ) ;
free( p ) ;
p = q ;
-- ( *G ).arcnum ;
}
-- ( *G ).vexnum ; //注意处理对下面的影响for( i = k ; i < ( *G ).vexnum ; ++ i ) //(2)
( *G ).vertices[ i ] = ( *G ).vertices[ i + 1 ] ;//data和firstarc一起前移for( i = 0 ; i < ( *G ).vexnum ; ++ i ) //删除以u为入度的弧或边,以及改变相应结点的位置(3)
{
p = ( *G ).vertices[ i ].firstarc ;
while( p )
{
if( p->adjvex == k )
{
if( p == ( *G ).vertices[ i ].firstarc )//要删除的为第一个邻接点
{
( *G ).vertices[ i ].firstarc = p->nextarc ;
if( ( *G ).kind % 2 ) //网
free( p->info ) ;
free( p ) ;
p = ( *G ).vertices[ i ].firstarc ; //重新连接
if( ( *G ).kind < 2 ) //有向 Take care! 对无向没有影响!
-- ( *G ).arcnum ;
}
else //要删除的非第一个邻接点
{
q = p->nextarc ;
if( ( *G ).kind % 2 )
free( p->info ) ;
free( p ) ;
p = q ;
if( ( *G ).kind < 2 )
-- ( *G ).arcnum ;
}
}
else
{
if( p->adjvex > k ) //k前面的结点未移动
-- p->adjvex ; //修改表结点的顶点位置值(序号)
p = p->nextarc ;
}
}// while
}// for
return OK ;
}Status InsertArc( ALGraph *G , VertexType u , VertexType w )//增加一条从u到w的弧或边
{
int i , j ;
ArcNode *p ;
InfoType inform ;i = LocateVex( *G , u ) ;
j = LocateVex( *G , w ) ;if( i < 0 || j < 0 )
return ERROR ;
p = ( ArcNode * )malloc( sizeof( ArcNode ) ) ;
p->adjvex = j ; //adjvex
if( ( *G ).kind % 2 ) //网
{
p->info = ( InfoType * )malloc( sizeof( InfoType ) ) ;
printf( "请输入%s到%s的弧或边的权值" , u , w ) ;
scanf( "%d" , &inform ) ;
*( p->info ) = inform ; //info
}
else
p->info = NULL ;p->nextarc = ( *G ).vertices[ i ].firstarc ; //nextarc (插入到表头)
( *G ).vertices[ i ].firstarc = p ;if( ( *G ).kind > 1 ) //无向,需生成另一条弧或边(从w到u)
{
p = ( ArcNode * )malloc( sizeof( ArcNode ) ) ;
p->adjvex = i ;if( ( *G ).kind == 3 ) //无向网
{
p->info = ( InfoType * )malloc( sizeof( InfoType ) ) ;
*( p->info ) = inform ;
}
else
p->info = NULL ;p->nextarc = ( *G ).vertices[ j ].firstarc ;
( *G ).vertices[ j ].firstarc = p ;
}
return OK ;
}Status DeleteArc( ALGraph *G , VertexType u , VertexType w )//删除一条从u到w的弧或边
{
int i , j ;
ArcNode *p , *q ;i = LocateVex( *G , u ) ;
j = LocateVex( *G , w ) ;
if( i < 0 || j < 0 )
return ERROR ;p = ( *G ).vertices[ i ].firstarc ;
while( p && p->adjvex != j )
{
q = p ;
p = p->nextarc ;
} //跳出时,q为p的前一个弧结点
if( p && p->adjvex == j ) //找到待删除的弧或边
{
if( p == ( *G ).vertices[ i ].firstarc ) //为头结点
( *G ).vertices[ i ].firstarc = p->nextarc ;
else //非头结点
q->nextarc = p->nextarc ; //指向下一条弧或边if( ( *G ).kind % 2 ) //网
free( p->info ) ;
free( p ) ;
-- ( *G ).arcnum ;
}// if
if( ( *G ).kind > 1 ) //无向,删除对称的w到u的弧或边
{
p = ( *G ).vertices[ j ].firstarc ;
while( p && p->adjvex != i )
{
q = p ;
p = p->nextarc ;
}
if( p && p->adjvex == i )
{
if( p == ( *G ).vertices[ j ].firstarc )
( *G ).vertices[ j ].firstarc = p->nextarc ;
else
q->nextarc = p->nextarc ;if( ( *G ).kind % 2 )
free( p->info ) ;
free( p ) ;
}
}// if
return OK ;
}//-----------------------Depth First Search----------------------------//
#ifndef Boolean
#define Boolean unsigned char
#endifBoolean visited[ MAX_VERTEX_NUM ] ;
Status ( *VisitFunc )( VertexType u ) ; //函数变量(留心)Status DFS( ALGraph G , int v ) //从第v个顶点出发递归地深度优先遍历图G
{
int w ;visited[ v ] = TRUE ;
VisitFunc( G.vertices[ v ].data ) ; //访问第v个顶点
for( w = FirstAdjVex( G , G.vertices[ v ].data ) ; w >= 0 ; w = NextAdjVex( G , G.vertices[ v ].data , G.vertices[ w ].data ) )
{
if( visited[ w ] != TRUE )
DFS( G , w ) ;
}
return OK ;
}Status DFSTraverse( ALGraph G , Status ( *v )( VertexType v ) )
{
int u ;VisitFunc = v ; //使用全局遍历VisitFunc,使DFS不必设函数指针参数
for( u = 0 ; u < G.vexnum ; ++ u )
{
visited[ u ] = FALSE ; //访问标志数组初始化
}
for( u = 0 ; u < G.vexnum ; ++ u )
{
if( visited[ u ] == FALSE )
DFS( G , u ) ;
}return OK ;
}Status visit( VertexType u )
{
puts( u ) ; //随定义的类型而变
return OK ;
}//----------------------------Breadth First Search --------------------------------//
Status BFSTraverse( ALGraph G , Status ( *v )( VertexType v ) )
{
int u , w , q;
LinkQueue Q ;for( u = 0 ; u < G.vexnum ; ++ u )
{
visited[ u ] = FALSE ;
}
InitQueue( &Q ) ;
for( u = 0 ; u < G.vexnum ; ++ u )
{
if( !visited[ u ] ) //u尚未被访问
{
visited[ u ] = TRUE ;
v( G.vertices[ u ].data ) ;
EnQueue( &Q , u ) ; //u号入队列
while( !QueueEmpty( Q ) )
{
DeQueue( &Q , &q ) ;
for( w = FirstAdjVex( G , G.vertices[ q ].data ) ; w >= 0 ; w = NextAdjVex( G , G.vertices[ q ].data , G.vertices[ w ].data ) )
if( !visited[ w ] ) //w为q的尚未访问的邻接顶点
{
visited[ w ] = TRUE ;
v( G.vertices[ w ].data ) ;
EnQueue( &Q , w ) ;
}
}//while
}//if
}//for
return OK ;
}//---------------------------Output------------------------------//
Status Output( ALGraph G )
{
int i ;
char s[ 7 ] , sa[ 4 ] ;
ArcNode *p ;switch( G.kind )
{
case DG: strcpy( s , "有向图" ) ;
strcpy( sa , "弧" ) ;
break ;
case DN: strcpy( s , "有向网" );
strcpy( sa , "弧" ) ;
break ;
case UDG:strcpy( s , "无向图" ) ;
strcpy( sa , "边" ) ;
break ;
default: strcpy( s , "无向网" ) ;
strcpy( sa , "边" ) ;
}printf( "\n输出含有%d顶点和%d条%s的%s:" , G.vexnum , G.arcnum , sa , s ) ;
printf( "\nOutput the vexs:\n" ) ; //输出顶点序列
for( i = 0 ; i < G.vexnum ; ++ i )
{
printf( "G.vertices[ %d ].data = " , i ) ;
puts( G.vertices[ i ].data ) ; //根据VertexType而变化
}printf( "\nOutput the arc:\n" ) ; //输出弧或边
printf( "Vex1(弧尾) Vex2(弧头) 该%s信息:\n" , sa ) ;
for( i = 0 ; i < G.vexnum ; ++ i )
{
p = G.vertices[ i ].firstarc ;
while( p )
{
if( G.kind < 2 ) //有向
{
printf( "%s ----------> %s\n" , G.vertices[ i ].data , G.vertices[ p->adjvex ].data ) ;
}
else //无向
{
if( i < p->adjvex ) //保证只输出一次
printf( "%s ----------> %s\n" , G.vertices[ i ].data , G.vertices[ p->adjvex ].data ) ;
}
if( G.kind % 2 )
printf( ":%d" , *( p->info ) ) ;
p = p->nextarc ;
}
}
return OK ;
}//---------------------------------------------------------------------------------//
//----------------------------------Main Fuction-----------------------------------//
int main( void )
{
ALGraph G ;CreateGraph( &G ) ; //Input: 3,2 ; 0 ; a,b,c ; a->b , b->c ;
Output( G ) ;
printf( "\n" ) ;
// puts( *GetVex( G , 2 ) ) ;
// PutVex( &G , "a" , "d" ) ;
// Output( G ) ;// FirstAdjVex( G , "a" ) ;
// NextAdjVex( G , "a" , "c" ) ; //Input: a->b ; a->c ; a->d// InserVex( &G , "d" ) ;
// Output( G ) ;// DeleteVex( &G , "a" ) ;
// Output( G ) ;// InsertArc( &G , "a" , "c" ) ;
// Output( G ) ;// DeleteArc( &G , "a" , "c" ) ; //Input: a->b ; a->c ; a->d
// Output( G ) ;DFSTraverse( G , visit ) ; //Input: a->b ; a->c ; c->d
// BFSTraverse( G , visit ) ; //Input: a->b ; a->c ; c->dreturn 0 ;
}
- 第七章(2).图的邻接表存储表示
- 数据结构编程笔记十九:第七章 图 图的邻接表存储表示及各基本操作的实现
- 20.图的存储表示-----------------邻接表
- 数据结构:图的邻接表存储表示
- 图的存储表示--邻接表实现
- 图的基本概念;图的存储表示:邻接矩阵、邻接表
- 图(网)的存储结构(数组存储表示即邻接矩阵、邻接表)
- 图的邻接表存储结构表示法
- 21.图的存储表示 ------------------------邻接多重表
- C语言:实现图的邻接表存储表示
- 图的表示--邻接表
- 图的表示--邻接表
- 第七章(3).图的十字链表存储表示
- 数据结构:无向图的邻接多重表存储表示 (c实现)
- 数据结构之图的存储表示(邻接矩阵、邻接表和边集数组)
- 第七章(1).图的数组(邻接矩阵)存储表示
- 图的邻接表的表示方法
- 图的存储结构(邻接表)
- 第六章(5).树的孩子兄弟表示法
- Linux crontab定时执行任务 命令格式与详细例子
- 第六章(6).三叉链表存储树
- 第六章(7).哈夫曼树及其应用
- 第七章(1).图的数组(邻接矩阵)存储表示
- 第七章(2).图的邻接表存储表示
- 第七章(3).图的十字链表存储表示
- 第七章(5).非连通图的生成森林
- 第七章(6).最小生成树
- 第七章(7).关结点和重连通分量
- 第七章(8).拓扑排序
- 第七章(9).关键路径
- 第七章(10).单源最短路径
- synchronized 关键字最佳实践