第七章(6).最小生成树

来源:互联网 发布:淘宝500的充气娃娃图片 编辑:程序博客网 时间:2024/06/08 11:42

//由MiniSpanTree_PRIM()可知Prim算法的时间复杂度为O(n*n),(n为顶点数)与网中的边数无关,因此使用于求边稠密的网的最小生成树。
//而Kruskal算法恰恰相反,它的时间复杂度为O(e*log e),(e为网中边的数目)。它比较适合求边稀疏的网的最小生成树。
#include < stdio.h >
#include < stdlib.h >
#include < string.h >

#define TRUE 1  
#define FALSE 0    
#define OK 1
#define ERROR 0
#define OVERFLOW -2 

typedef int Status ;

//---------------图的数组(邻接矩阵)存储表示------------------//

#define INFINITY 2147483647    //最大值(无穷大)INT_MAX = 2147483647
#define MAX_VERTEX_NUM 20    //最大顶点个数(vertex顶点)
#define MAX_INFO 20      //关于边的信息的字符串长度
#define MAX_NAME 5      //关于顶点信息的字符串长度

typedef int VRType ;     //此处考虑无权图
typedef char InfoType ;
typedef char VertexType[MAX_NAME];  //VertexType可以根据实际情况灵活设定类型!int,float,char…

typedef enum{ DG , DN , UDG , UDN }GrapKind ; //{有向图(Digraph),有向网(Digraph Network), 无向图(Undigraph),无向网(Undigraph Network)}

typedef struct ArcCell
{
 VRType adj ;  //VRType是顶点关系类型。对于无权图,用1或0表示相邻否。对于带权图,则为权值类型。
 InfoType *info ; //该弧(Arc)相关的信息的指针
} ArcCell , AdjMatrix[ MAX_VERTEX_NUM ][ MAX_VERTEX_NUM ] ;

typedef struct
{
 VertexType vexs[ MAX_VERTEX_NUM ] ; //顶点向量
 AdjMatrix arcs ;     //邻接矩阵
 int vexnum , arcnum ;    //图的当前顶点数和弧树
 GrapKind kind ;
} MGraph ;

Status InitGraph( MGraph *G ) ;
Status InputInformation( MGraph *G , int i , int j ) ;
Status LocateVex( MGraph G , VertexType u ) ;
Status CreateUDN( MGraph *G ) ;

//----------------------------------------------------------------------------------//

typedef struct   // 记录从顶点集U到V-U的代价最小的边的辅助数组定义
{
   VertexType adjvex ;
   VRType  lowcost ;
} MinSide[ MAX_VERTEX_NUM ] ;

void MiniSpanTree_PRIM( MGraph G , VertexType u ) ;
int minimum( MinSide ms , MGraph G ) ;

 

#include "head.h"

//--------------------Basic Fuction about the UDN---------------------//

Status InitGraph( MGraph *G )
{
 int i , j ;
 
 printf( "Input the number of Vertex and Arc : " ) ;
 scanf( "%d %d" , &( *G ).vexnum , &( *G ).arcnum ) ;  
 
 printf("Input the vector of %d vex( %d char ): \n" , ( *G ).vexnum , MAX_NAME ) ;
 for( i = 0 ; i < ( *G ).vexnum ; ++ i )  //构造顶点向量  Input:a b c d …(输入字符处理)
 {
  scanf( "%s" , ( *G ).vexs[ i ] ) ;  //访存错误,因为无内存。刚开始定义typedef char* VertexType;  所以( *G ).vexs[ i ]只是一个没有空间的指针
 }       
 
 for( i = 0 ; i < ( *G ).vexnum ; ++ i )  //初始化邻接矩阵
 {
  for( j = 0 ; j < ( *G ).vexnum ; ++ j )
  {   
   ( *G ).arcs[ i ][ j ].adj =  INFINITY ; //{adj , info}网  INFINITY等效于无穷大  
   ( *G ).arcs[ i ][ j ].info = NULL ;
  }
 }

 return OK ;
}

Status InputInformation( MGraph *G , int i , int j )
{
 char s[ MAX_INFO ] , *info ;
 int w ;
 
 printf("请输入该边的相关信息(%d个字符): ", MAX_INFO ) ;
 gets( s );
 w = strlen( s ) ;
 if( w )
 {
  info = ( char * )malloc( ( w + 1 ) * sizeof( char ) ) ;
  strcpy( info , s ) ;
  ( *G ).arcs[ i ][ j ].info = info ;
 }
 return OK ;
}

Status LocateVex( MGraph G , VertexType u ) //若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 
{
 int i ;
 
 for( i = 0 ; i < G.vexnum ; ++ i )
 {
  if( strcmp( u , G.vexs[ i ] ) == 0 )
   return i ;
 }
 return EOF ;   //EOF means -1 .
}

Status CreateUDN( MGraph *G )  //构造无向网*G
{
 int i , j , k , w ;
 int IncInfo ;
 VertexType va , vb ; 
 // va = vb = NULL ;  //typedef char VertexType[MAX_NAME];后,va,vb实际上是一个数组名,有空间!而指针则需要初始化
 
 InitGraph( G ) ;
 printf( "It's there any information for arc?( 1 means yes ): " ) ;
 scanf( "%d" , &IncInfo ) ;
 printf( "请输入%d条弧的边尾、边头以及权值: \n" , ( *G ).arcnum ) ;

 for( k = 0 ; k < ( *G ).arcnum ; ++ k )  //构造邻接矩阵
 {
  scanf( "%s%s%d%*c", va , vb , &w ) ; //%*c吃掉回车符 //输入一条边依附的顶点及权值  (va, vb输入字符处理)
  i = LocateVex( *G , va ) ;
  j = LocateVex( *G , vb ) ;
  ( *G ).arcs[ i ][ j ].adj = w ;   //弧< va , vb >的权值  
  
  if( IncInfo )       //若弧含有相关信息,则输入
  {
   InputInformation( G , i , j ) ;   
  }  
  ( *G ).arcs[ j ][ i ] = ( *G ).arcs[ i ][ j ] ;  // adj and info.
 }
 ( *G ).kind = UDN ;       //此处UDN为3,这是在enun中决定的!
 
 return OK ; 
}

//-----------------Function for MinSpanTree-------------------------------//

void MiniSpanTree_PRIM( MGraph G , VertexType u )//用Prim算法从顶点u出发构造网G的最小生成树T,输出T的各条边.
{
 int k , i , j  ;
 MinSide closedge ;

 k = LocateVex( G , u ) ;
 for( j = 0 ; j < G.vexnum ; ++ j )  //初始化辅助数组
 {
  if( j != k )
  {
   strcpy( closedge[ j ].adjvex , u ) ;
   closedge[ j ].lowcost = G.arcs[ k ][ j ].adj ;
  }
 }
 closedge[ k ].lowcost = 0 ;  //初始,U = { u } ;

 for( i = 1 ; i < G.vexnum ; ++ i )  //选择其余的G.vexnum - 1 个顶点.
 {
  k = minimum( closedge , G ) ;   //求出T的下一个结点:第K顶点
  printf( "%s---------------->%s\n" , closedge[ k ].adjvex , G.vexs[ k ] ) ;
  closedge[ k ].lowcost = 0 ;   //将第K个顶点并入U集

  for( j = 0 ; j < G.vexnum ; ++ j )
  {
   if( G.arcs[ k ][ j ].adj < closedge[ j ].lowcost ) //新顶点并入U后重新选择最小边
   {
    strcpy( closedge[ j ].adjvex , G.vexs[ k ] ) ;
    closedge[ j ].lowcost = G.arcs[ k ][ j ].adj ;
   }
  }
 } 
}

int minimum( MinSide ms , MGraph G )    //求closedge.lowcost的最小值
{
 int j , k , min , i = 0 ;

 while( !ms[ i ].lowcost ) //排除等于0的,即属于集合U的。
  ++ i ;

 min = ms[ i ].lowcost ;  //第一个不为0的值.
 k = i ;
 for( j = i + 1 ; j < G.vexnum ; ++ j )
 {
  if( ms[ j ].lowcost > 0 && min > ms[ j ].lowcost ) //ms[ j ].lowcost仅仅为了程序的健壮性。
  {
   min = ms[ j ].lowcost ;
   k = j ;
  }
 }
 return k ;
}

int main( )
{
 MGraph G ;
    
// closedge[ 0 ].lowcost = 10 ;   //悲催!无点引用!不过可以执行通过,应该是编译器的原因。
// printf( "%d\n" , closedge[ 0 ].lowcost ) ;

 CreateUDN( &G ) ;
 MiniSpanTree_PRIM( G , G.vexs[ 0 ] ) ;  //Oh! So Cool!

 return 0 ;
}


0 0
原创粉丝点击