寻找具有树特征无向图的最小高度树---C语言

== 一、问题来源==

对于一个具有树特征的无向图,我们可选择任何一个节点作为根。图因此可以成为树,在所有可能的树中,具有最小高度的树被称为最小高度树。给出这样的一个图,写出一个函数找到所有的最小高度树并返回他们的根节点。该图包含n个节点,标记为0到n-1。给定数字n和一个无向边edges列表(每一个边都是一对标签)你可以假设没有重复的边会出现在edges 中。由于所有的边都是无向边,[0,1] 和[1,0]是相同的,因此不会同时出现在edges 里。

示例1:

输入: n=4, edges =[[1, 0],[1, 2],[1, 3]]

0

|

1

/ \

2 3

输出:【1】

示例2:

输入: n=6, edges = [[O, 3],[1, 3],[2, 3], [4,3],[5, 4]]

0 1 2

\ | /

3

|

4

|

5

输出: [3, 4]

说明:
根据[树的定义],树是一个无向图,其中任何两个顶点只通过一条路径连接。换句话说,一个任何没有简单环路的连通图都是一棵树。
树的高度是指根节点和叶子节点之间最长向下路径.上边的数量。

二、心路历程

使用C语言来解决摘要中所述的在无向图中寻找最小高度树的问题,对于一个没有学过数据结构的小白来讲,为了弄明白解题的整个过程差点挠光了头发。起初在网络上寻找相关的解题方法,简单的一搜,哦豁,是一道经典的leedcode题目,可参考的博客多如牛毛。此时心里那是美滋滋的,又可以白嫖一下前辈们的智慧结晶啦。可是事情如果如此简单,就不会诞生今天这一篇分享啦。当我满怀期待的打开一篇篇博客的时候,看到C++/java实现,我那脆弱的小心脏就逐渐变得哇凉哇凉的。C++没学过啊,Java我也不会啊。那你还会啥?我就会个C,还是没啥编程经验的那种。这可咋办呀,看了他们的解题思路。嗯,无向图,广度优先搜索?拓扑结构?越看越懵,这时候心里慌的一批。既然看不懂,就不掩耳盗铃了。求人不如求己,自己先分析问题,恶补一下数据结构的知识,然后跟几位有经验的同事讨论了一下,整理出了自己的解题思路。

三、解题思路

建立无向图 -> 遍历无向图 -> 对称性 -> 依次去除叶节点

无向图是由定点和边两部份组成。表示图的方法有很多种,经过对比,我选择了使用邻接矩阵来表示图。因为相比于链表更容易让人理解,且运用无向图在邻接矩阵中的对称特性,可以很直观的判定无向图中每一个顶点的度。

邻接矩阵
在这里插入图片描述
如上图所示:图的邻接矩阵存储方式是用两个数组来表示图。一个意为数组存储图中的顶点信息,一个二维数组(称为邻接矩阵)存储图中边的信息。

有了这个矩阵我们就可以直观的看出图中的信息:

1、顶点之间有联系,将他们的所在边的度置为 1;

2、某个顶点的度,其实就是这个定点v(i)在邻接矩阵中第i行的(或者第i列)的元素之和,例如v(1)的度就是1+0+1+0=2;

3、顶点v(i)的所有邻接点就是矩阵中第i行arc(i)(j)为 1 的点;

4、无向图中顶点指向是相互的,所以arc(i)(j)的值呈主对角线对称分布;

每次遍历邻接矩阵,得出度为1的顶点,此顶点在树结构中一定是叶节点。根据无向图在邻接矩阵中的对称原理,将该点与临界点对应的连接边的度均置为0,即完成了剪树叶的操作。执行递归操作,直至剩余1~2个顶点,它们就是我们寻找的最小高度树的根节点。

四、示例2测试

在这里插入图片描述

五、代码示例(完整)

/*******************************************************************************
* Filename:
*	FMHT 
*Description:
*	Find the Minimum Height Tree
*Author:
	QH
*Time:
	2020.8.24 
********************************************************************************/

#include <stdio.h>

typedef int VertexType;
typedef int EdgeType;
#define MAXVEX 100
#define ZERO 0


typedef struct{
    
    
	VertexType vexs[MAXVEX];
	EdgeType arc[MAXVEX][MAXVEX];
	int numVertexes, numEdges;
} MGraph;

void CreateMGraph(MGraph *G);
void RemoveLeave(MGraph *G);

int main(){
    
    
	//Building undirected graph with adjacency matrix
	MGraph G;
	CreateMGraph(&G);
	printf("Output the root node of the minimum height tree\n");
	RemoveLeave(&G);
	
	return 0;
}

/*******************************************************************************
*****************
* FUNCTION
*	CreateMGraph
*DESCRIPTION
*	Representstion of undirected graph by adjacency matrix.
*PARAMETERS
*	G		[MGraph *]		structure
*RETURNS
*	void
*****************
*******************************************************************************/

void CreateMGraph(MGraph *G){
    
    
	int i, j, k;
	printf("Please enter the number of vertexes and edges:");
	scanf("%d,%d", &G -> numVertexes, &G -> numEdges);
	printf("Please enter vertex:\n");
	for (i = 0; i < G -> numVertexes; i ++)
		scanf("%d", &G -> vexs[i]);
		
	for (i = 0; i < G -> numVertexes; i ++)
		for (j = 0; j < G -> numVertexes; j ++)
			G -> arc[i][j] = ZERO;
	for (k = 0; k < G -> numEdges; k ++){
    
    
		printf("please enter (vi,vj):");
		scanf("%d, %d", &i, &j);
		G -> arc[i][j] = 1;
		G -> arc[j][i] = G -> arc[i][j];
	}
	//Adjacency matrix of output undirected graph
	printf("Adjacency matrix of output undirected graph:\n");
	for (i = 0; i < G -> numVertexes; i ++){
    
    
		for (j = 0; j < G -> numVertexes; j ++){
    
    
				printf("%d\t", G -> arc[i][j]);
			}
		printf("\n");
	}

}

/*******************************************************************************
*****************
* FUNCTION
*	RemoveLeave
*DESCRIPTION
*	Use recursive loops to remove leaf nodes layer by layer.
*PARAMETERS
*	G		[MGraph *]		structure
*RETURNS
*	void
*****************
*******************************************************************************/

void RemoveLeave(MGraph *G){
    
    
	int i, j;	//for circulation
	int sum;	//Sum of connected edges of each vertex
	int n = 0;	//Number of remaining vertices
	int m[G -> numVertexes];	//save 
	//initialize m[]
	for (i = 0; i < G -> numVertexes; i ++){
    
    
		m[i] = ZERO;
	}
	//Determine whether the vertex is a leaf. yes set 1,not set 2	
	for (i = 0; i < G -> numVertexes; i ++){
    
    
		sum = 0;
		for (j = 0; j < G -> numVertexes; j ++){
    
    
				sum = sum + G -> arc[i][j];
				if (sum > 1){
    
    
					n = n + 1;
					m[i] = 2;
					break;
				}
				if (sum == 1){
    
    
					m[i] = 1;	//leaf
				}	
			}
	}
	//remove leaf
	for (i = 0; i < G -> numVertexes; i ++){
    
    
		if (m[i] == 1){
    
    
			for (j = 0; j < G -> numVertexes; j ++){
    
    
				G -> arc[i][j] = 0;
				G -> arc[j][i] = 0;
			}
		}
		if (m[i] == 2){
    
    
			if (n < 3){
    
    
				//Output the root node of the minimum height tree 
				printf("%d\t", G -> vexs[i]);
			}
		}		
	}
	//Recursion and termination condition judgment	
	if (n < 3){
    
    
			return ;
		}
	else{
    
    
		RemoveLeave(G);
	}
}

猜你喜欢

转载自blog.csdn.net/Fighting_gua_biu/article/details/112258425