核心思想:
图是树需要满足两个条件:
(1)图中结点均连通,即结点属于同一个集合;
(2)结点满足只有一个结点入度为0,其余结点入度为1;
算法步骤:
(1)一次读入一条边,将读入的边对相应的两个结点分别初始化,若该点之前不存在,则创建一个包含该点的新集合;同时,对于后面的结点,入度要进行加1;
(2)比较该边的两个端点是否在同一个集合,若不在则将该边的两个端点所在的两个集合进行合并;
(3)重复步骤(1)、(2),直到输入结束;
(4)根据图是树的条件去进行判断,满足则是树,否则不是树。
实例以及代码
//定义图结点的数据结构
typedef struct{
int number; //结点的编号
int home; //结点属于的集合编号
int ru; //结点的入度
}Dian;
int k=0; //结点个数
//对于输入的每个结点,进行相应的初始化
//返回的是该结点在结构体数组g[]中的下标
int AddDot(Dian g[],int a,int t){
int i;
for(i=0;i<k;i++)
if(a==g[i].number)
{
if(t==1) //这里有个易错点,就是当点
g[i].ru++;//存在时,会选择直接退出
return i;
}
g[k].number=a;
g[k].home=a;
g[k++].ru=0;
if(t==1)
g[k-1].ru++;
return k-1;
}
//判断边两个端点是否属于一个集合,若不,则将两个集合合并
void Merge(Dian g[],int loc1,int loc2){
int t,i;
t=g[loc1].home;
for(i=0;i<k;i++)
if(g[i].home==t)
g[i].home=g[loc2].home;
}
//读入数据的模块
void Input(Dian g[]){
int a,b,loc1,loc2;
printf("请输入边(以0 0作为结束):\n");
scanf("%d %d",&a,&b);
while(a!=0)
{
loc1=AddDot(g,a,0);
loc2=AddDot(g,b,1);
Merge(g,loc1,loc2);
scanf("%d %d",&a,&b);
}
}
//根据已有数据进行判断
bool Judge(Dian g[]){
int i,t,mark=0;
t=g[0].home;
for(i=0;i<k;i++)
{
if(g[i].home!=t) //若结点不属于同一集合,则F
return false;
if(g[i].ru>1) //如某一个结点的入度大于1,则F
return false;
if(g[i].ru==0) //记录结点入度为0的结点数
mark++;
}
if(mark!=1) //若个数不为1,则返回F
return false;
return true; //否则,返回T
}
//格式化输出
void Output(bool t){
if(t)
printf("可以构成一棵树。");
else
printf("无法构成一棵树");
}
//主函数,负责上述函数的调用
int main(){
Dian g[20];
bool Tree;
Input(g);
Tree=Judge(g);
Output(Tree);
return 0;
}
运行结果: