一、图的生成树
设E(G)为连通图G中所有边的集合,则从图中任意顶点出发遍历图时,必将E(G)分成两个集合T(G)和B(G),其中T(G)是遍历过程中经历边的集合;B(G)是剩余的边的集合。显然T(G)和图G中所有顶点一起构成连通图G的极小连通子图,即可知它是连通图的一颗生成树。
二、生成树的构造方法
1、通过深度优先遍历构建图的生成树
2、对于非连通图,通过这样的遍历得到的是生成森林
三、以孩子兄弟链表表示法作为生成森林的存储结构
/*
*定义树孩子兄弟表示的存储结构
*/
typedef struct treenode
{
VertexType data[3] ; //存储结点数据
struct treenode *firstson ; //第一个孩子节点
struct treenode *next ; //第一个孩子节点的兄弟节点
} *CSTree , CSNode ;
四、通过深度优先遍历生成森林算法
/*
*建立无向图G的深度优先生成森林的孩子兄弟链表T
*/
CSTree DFSForest(ALGraph G , CSTree T)
{
int i , j ;
CSNode *p ;
CSTree q ;
T = NULL ;
for(i = 0 ; i < G.n ; i++)
{
visited[i] = 0 ;
}
for(i = 0 ; i < G.n ; i++)
{
if(!visited[i])
{
p = (CSTree)malloc(sizeof(CSNode)) ;
//给根节点赋值
for(j = 0 ; j < 3 ; j++)
{
p->data[j] = G.adjList[i].vertex[j] ;
}
p->firstson = NULL ;
p->next = NULL ;
if(!T)
{
T = p ;
q = T ;
}
else
{
q->next = p ;
}
q = p ;
DFSTree(G , i , p) ; //建立以p为根节点的生成树
}
}
return T ;
}
五、生成树算法
void DFSTree(ALGraph G , int i , CSTree T)
{
int j , first = 1 ;
EdgeNode *w ;
CSNode *p , *q;
q = T ;
visited[i] = 1 ;
for(w = G.adjList[i].firstedge ; w ; w = w->next)
{
if(!visited[w->adjvex])
{
p = (CSTree)malloc(sizeof(CSNode)) ;
for(j = 0 ; j < 3 ; j++)
{
p->data[j] = G.adjList[w->adjvex].vertex[j] ;
}
p->firstson = NULL ;
p->next = NULL ;
if(first)
{
T->firstson = p ;
first = 0 ;
}
else
{
q->next = p ;
}
q = p ;
DFSTree(G , w->adjvex , q) ;
}
}
}
六、测试代码
/*
*以及深度优先遍历得到图的生成森林,以孩子兄弟链表表示法作生成森林的存储结构
*/
#include<stdio.h>
#include<malloc.h>
#define MaxVerNum 100 /*定义最大节点数*/
int visited[MaxVerNum] ;
typedef char VertexType ;
typedef struct node
{
int adjvex ;
struct node *next ; //指向下一个邻接节点域
} EdgeNode ;
typedef struct vnode
{
VertexType vertex[3] ; //顶点域
EdgeNode *firstedge ; //边表头指针
} VertexNode ;
typedef VertexNode AdjList[MaxVerNum] ;
/*
*定义以邻接边为存储类型的图
*/
typedef struct
{
AdjList adjList ; //邻接表
int n , e ; //顶点数与边数
} ALGraph ;
/*
*定义树孩子兄弟表示的存储结构
*/
typedef struct treenode
{
VertexType data[3] ; //存储结点数据
struct treenode *firstson ; //第一个孩子节点
struct treenode *next ; //第一个孩子节点的兄弟节点
} *CSTree , CSNode ;
void DFSTree(ALGraph G , int i , CSTree T)
{
int j , first = 1 ;
EdgeNode *w ;
CSNode *p , *q;
q = T ;
visited[i] = 1 ;
for(w = G.adjList[i].firstedge ; w ; w = w->next)
{
if(!visited[w->adjvex])
{
p = (CSTree)malloc(sizeof(CSNode)) ;
for(j = 0 ; j < 3 ; j++)
{
p->data[j] = G.adjList[w->adjvex].vertex[j] ;
}
p->firstson = NULL ;
p->next = NULL ;
if(first)
{
T->firstson = p ;
first = 0 ;
}
else
{
q->next = p ;
}
q = p ;
DFSTree(G , w->adjvex , q) ;
}
}
}
/*
*建立无向图G的深度优先生成森林的孩子兄弟链表T
*/
CSTree DFSForest(ALGraph G , CSTree T)
{
int i , j ;
CSNode *p ;
CSTree q ;
T = NULL ;
for(i = 0 ; i < G.n ; i++)
{
visited[i] = 0 ;
}
for(i = 0 ; i < G.n ; i++)
{
if(!visited[i])
{
p = (CSTree)malloc(sizeof(CSNode)) ;
//给根节点赋值
for(j = 0 ; j < 3 ; j++)
{
p->data[j] = G.adjList[i].vertex[j] ;
}
p->firstson = NULL ;
p->next = NULL ;
if(!T)
{
T = p ;
q = T ;
}
else
{
q->next = p ;
}
q = p ;
DFSTree(G , i , p) ; //建立以p为根节点的生成树
}
}
return T ;
}
/*
*建立无向图的邻接表存储
*/
void CreateALGraph(ALGraph *G)
{
int i , j , k ;
EdgeNode *s ;
printf("请输入顶点数与边数(输入格式为:顶点数,边数): ") ;
scanf("%d,%d" , &G->n , &G->e) ;
printf("请输入顶点信息(输入格式为:顶点号<CR>):\n") ;
for( i = 0 ; i < G->n ; i++)
{
scanf("%s" , G->adjList[i].vertex) ;
G->adjList[i].firstedge = NULL ; //将顶点的边表头指针设置为空
}
printf("请输入边的信息(输入格式为:i,j):\n") ;
for(k = 0 ; k < G->e ; k++)
{
scanf("%d,%d" , &i , &j) ;
s = (VertexNode*)malloc(sizeof(VertexNode)) ;
//边上的第一个节点
s->adjvex = j ;
s->next = G->adjList[i].firstedge ;
G->adjList[i].firstedge = s ;
//边上的第二个节点
s = (VertexNode*)malloc(sizeof(VertexNode)) ;
s->adjvex = i ;
s->next = G->adjList[j].firstedge ;
G->adjList[j].firstedge = s ;
}
}
/*
*进行森林的先根遍历
*/
void PreForest(CSTree T)
{
if(T)
{
printf("%s " , T->data) ;
PreForest(T->firstson) ;
while((T = T->next))
{
PreForest(T) ;
}
}
}
/*
*进行生成树的测试
*/
void main()
{
ALGraph *G ;
CSTree T ;
G = (ALGraph*)malloc(sizeof(ALGraph)) ;
T = (CSTree)malloc(sizeof(CSNode)) ;
CreateALGraph(G) ;
T = DFSForest(*G , T) ;
//进行树森林的遍历
PreForest(T) ;
}