//对于非连通图,每个连通分量中的顶点集,和遍历时走过的边一起构成若干棵生成树,
//这些连通分量的生成树组成非连通图的生成森林。
//以孩子兄弟链表作为生成森林的存储结构,以下算法生成非连通图的深度优先生成森林。
//算法的时间复杂度为遍历算法相同.
#include <stdio.h>
#include <stdlib.h>
#define MAX 20
typedef char ElemType;
typedef enum {FALSE,TRUE} Boolean;
typedef int Status;
Boolean visited[MAX];
//邻接表结构表示的图
#include <limits.h>
#define MAX_VERTEX_NUM 20
#define OK 1
#define ERROR 0
typedef int InfoType; //定义弧相关信息为整形
typedef char VertexType; //定义顶点类型为字符型
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; //顶点数和弧数
}ALGraph; //邻接表表示的图结构
//树结构:孩子兄弟链
typedef struct CSNode
{
ElemType data;
struct CSNode *firstchild,*nextsibling;
}CSNode,*CSTree;
Status CreateUDG(ALGraph *G);
void DFSForest(ALGraph G,CSTree *T);
void DFSTree(ALGraph G,int v,CSTree *t);
int LocateVex(ALGraph G,VertexType v);
void CSTreeTraverse(CSTree T);
int FirstAdjVex(ALGraph G,int v);
int NextAdjVex(ALGraph G,int v,int w);
int main()
{
ALGraph *G;
G=(ALGraph *)malloc(sizeof(ALGraph));
CSTree T;
T=(CSTree)malloc(sizeof(CSNode));
CreateUDG(G);
int i;
printf("图结构:\n");
for(i=0;i<G->vexnum;i++)
{
ArcNode *p;
p=(ArcNode *)malloc(sizeof(ArcNode));
p=G->vertices[i].firstarc;
printf("%c ",G->vertices[i].data);
while(p)
{
VertexType t;
int k;
k=p->adjvex;
t=G->vertices[k].data;
printf("%c ",t);
p=p->nextarc;
}
printf("\n");
}
printf("广度优先搜索:\n");
DFSForest(*G,&T);
CSTreeTraverse(T);
return 0;
}
int LocateVex(ALGraph G,VertexType v)
{
int i;
for(i=0;i<G.vexnum;i++)
if(G.vertices[i].data==v)
return i;
return -1;
}
//创建无向图
Status CreateUDG(ALGraph *G)
{
int i,IncInfo;
printf("输入顶点数量:");
scanf("%d",&G->vexnum);
printf("输入弧数量:");
scanf("%d",&G->arcnum);
printf("弧是否含有其他信息(否---0,是---1):");
scanf("%d",&IncInfo);
//头结点处理
for(i=0;i<G->vexnum;i++)
{
fflush(stdin);
printf("输入第%d个顶点:",i+1);
scanf("%c",&G->vertices[i].data); //输入头结点的顶点信息
G->vertices[i].firstarc=NULL; //初始化头结点的弧指针
}
//弧结点处理
for(i=0;i<G->arcnum;i++)
{
char v1,v2;
int node1,node2;
fflush(stdin);
printf("输入第%d条弧的依附的第一个结点:",i+1);
scanf("%c",&v1);
fflush(stdin);
printf("输入第%d条弧的依附的第二个结点:",i+1);
scanf("%c",&v2);
node1=LocateVex(*G,v1);
node2=LocateVex(*G,v2);
ArcNode *p1,*p2;
//两个指针变量虽然是同一类型,但不能用一条分配内存语句同时分配,否则为同一指针变量,即指向同一地址
p1=(ArcNode *)malloc(sizeof(ArcNode));
p2=(ArcNode *)malloc(sizeof(ArcNode));
p1->adjvex=node1;
p2->adjvex=node2;
p1->nextarc=G->vertices[node2].firstarc;
G->vertices[node2].firstarc=p1;
p2->nextarc=G->vertices[node1].firstarc;
G->vertices[node1].firstarc=p2;
if(IncInfo)
{
int info;
printf("输入弧的其他信息:");
scanf("%d",&info);
p1->info=p2->info=&info;
}
else
p1->info=p2->info=NULL;
}
return OK;
}
//求位置v结点的第一个邻接点
int FirstAdjVex(ALGraph G,int v)
{
if(G.vertices[v].firstarc)
return G.vertices[v].firstarc->adjvex;
else
return -1;
}
//求位置v结点就w外的其他邻接点
int NextAdjVex(ALGraph G,int v,int w)
{
ArcNode *p;
p=(ArcNode *)malloc(sizeof(ArcNode));
p=G.vertices[v].firstarc;
while(p)
{
if(p->adjvex==w || visited[p->adjvex])
p=p->nextarc;
else
return p->adjvex;
}
return -1;
}
void DFSForest(ALGraph G,CSTree *T)
{
*T=NULL;
int v;
for(v=0;v<G.vexnum;v++)
visited[v]=FALSE;
CSTree q;
q=(CSTree)malloc(sizeof(CSNode));
for(v=0;v<G.vexnum;v++)
{
if(!visited[v])
{
CSTree p;
p=(CSTree)malloc(sizeof(CSNode));
p->data=G.vertices[v].data;
p->firstchild=NULL;
p->nextsibling=NULL;
if(!(*T))
*T=p;
else
q->nextsibling=p;
q=p;
DFSTree(G,v,&p);
}
}
}
void DFSTree(ALGraph G,int v,CSTree *t)
{
int w;
Boolean first;
first=TRUE;
visited[v]=TRUE;
CSTree n;
n=(CSTree)malloc(sizeof(CSNode));
for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w))
{
if(!visited[w])
{
CSTree m;
m=(CSTree)malloc(sizeof(CSNode));
m->data=G.vertices[w].data;
m->firstchild=NULL;
m->nextsibling=NULL;
if(first)
{
(*t)->firstchild=m; //1.如果位置w结点m是位置v结点的第一个邻接点,则将其作为孩子结点
first=FALSE;
}
else
{
n->nextsibling=m; //3.如果位置w结点m不是位置v结点的第一个邻接点,则将其作为上一个结点的兄弟结点
}
n=m; //2.将指针指向当前生成的结点
DFSTree(G,w,&m); //4.再从当前结点m出发进行深度遍历
}
}
}
//孩子兄弟链表表示的树的遍历
void CSTreeTraverse(CSTree T)
{
if(T)
{
printf("%c ",T->data);
printf("%c的兄弟:",T->data);
CSTreeTraverse(T->nextsibling);
printf("\n%c孩子:",T->data);
CSTreeTraverse(T->firstchild);
}
}