第七章(2).图的邻接表存储表示
2015-04-26 17:23
344 查看
//邻接表中,对图中每个顶点建立一个单链表,第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 -2 typedef 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 #endif Boolean 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->d return 0 ; }
相关文章推荐
- 数据结构编程笔记十九:第七章 图 图的邻接表存储表示及各基本操作的实现
- 图的邻接表存储表示示例讲解
- 数据结构编程笔记十八:第七章 图 图的邻接矩阵存储表示及各基本操作的实现
- 图(网)的存储结构(数组存储表示即邻接矩阵、邻接表)
- 图 - 图的存储结构 - 邻接表表示法
- 图的邻接表存储表示
- 数据结构:图的邻接表存储表示
- 数据结构之---C语言实现图的邻接表存储表示
- 20.图的存储表示-----------------邻接表
- 数据结构之图的存储表示(邻接矩阵、邻接表和边集数组)
- 图(网)的存储结构(数组存储表示即邻接矩阵、邻接表)
- 图的基本概念;图的存储表示:邻接矩阵、邻接表
- C语言:实现图的邻接表存储表示
- 图的邻接表存储表示 图的深度优先遍历和图的广度优先遍历
- 图算法------图的邻接表表示法(图的链式存储)
- 第七章(1).图的数组(邻接矩阵)存储表示
- 图的存储表示--邻接表实现
- 数据结构之---C语言实现图的邻接表存储表示
- 图的邻接表存储表示(C)
- 第七章(3).图的十字链表存储表示