设计算法判断给定的无向图是树(C++)(附源码,可以直接运行)

设计算法判断给定的无向图是树

从做完本次作业到写这篇博客已经过去了大概两三个月,对一些点可能已经忘记了。
中间也许有写的不好的地方,请大家见谅。

一、算法思想:
判断方法为使用DFS进行遍历,看是否可以将图节点全部遍历(判断是否是连通图),同时统计边数,判断是否为N-1。这两个条件缺一不可。即必须是连通图且边数为N-1(N为顶点个数)。
二、图的建立
首先一个比较困难的问题就是图的创建,我采用的是邻接表的形式创建的,有一个node1类型的数组ver,其用来存储节点的数据信息,每一个node1类型的struct都有一个data数据域和node2类型的指针域firstadj,用来指向其之后的节点信息。对于node2类型的struct,其也有两种类型的数据,一个是index,用来指示当前节点在之前数组的下标,还有一个就是nextadj,用来指向下一个以数组元素为箭头尾部的节点。具体如下边的代码。
同时还需要注意的一点就是,对于无向图的存储,我们使用邻接表存储的话,对其求边数,每个边数都统计了两遍的,最后得出的结果是要除以2才是真实的边数。
注释:由于我们使用的是邻接表存储图结构,每次输出拓扑排序的都是本邻接表所对应的拓扑排序。而图的邻接表可能有多种。对于求拓扑排序会有影响,但是对于我们的这次判断是否是树,邻接表只需要能表示出是哪个图就ok了。

struct node2 {
	int index;//在数据数组中的下标,如果顶点编号从1开始,则index对应减1
	node2* nextadj;//指向邻接表之后的节点
	node2() {
		index = -1;
		nextadj = NULL;
	}
};

struct node1 {
	int data;//具体顶点值
	node2* firstadj;//指向第一个节点
	node1() {
		firstadj = NULL;
		data = -1;
	}
};

对应到代码中就是我写的两个函数,一个创建顶点,一个创建边,大家仔细读一读就可以看懂,我就不过多叙述了。

	void create_ver();//创建图顶点信息
	void create_edge(int k, int length);//创建边信息

三、测试数据
1.第一个给出一个树来判断
在这里插入图片描述
判断结果如下:
在这里插入图片描述
2.再给出一个不是树的图
在这里插入图片描述
判断结果如下:
在这里插入图片描述

四、源代码
上述测试的两个图代码我都写在了下面。只需要将注释的改一改就可以了

#include<iostream>
#define v 6//V为定义的顶点数目
//#define v 7//V为定义的顶点数目
using namespace std;
struct node2 {
	int index;//在数据数组中的下标,如果顶点编号从1开始,则index对应减1
	node2* nextadj;//指向邻接表之后的节点
	node2() {
		index = -1;
		nextadj = NULL;
	}
};

struct node1 {
	int data;//具体顶点值
	node2* firstadj;//指向第一个节点
	node1() {
		firstadj = NULL;
		data = -1;
	}
};

//采用邻接表存储图
class Graph {
public:
	Graph();
	void create_ver();//创建图顶点信息
	void create_edge(int k, int length);//创建边信息
	void shuchu();//输出图的信息
	bool istree();//判断是否是树,算法1
	void DFS(int v0);//对图的遍历
private:
	node1 ver[v];//存储顶点信息
	bool visited[v];//存储是否访问过的信息
	int count;//遍历时记录边的个数
};
//构造函数
Graph::Graph()
{
	for (int i = 0; i < v; i++)//初始化数据数组
	{
		ver[i].data = -1;
		ver[i].firstadj =NULL ;
	}
	for (int i = 0; i < v; i++)//初始化标志数组
		visited[i] = false;
	count = 0;
}

void Graph::DFS(int v0)
{
	cout << ver[v0].data << " ";//访问第一个顶点
	visited[v0] = true;//改变标志
	node2* w = ver[v0].firstadj;//获得第一个邻接点
	while (w!=NULL)//如果有的话,则进行下列判断
	{
		count++;//此处找到一条表
		if (visited[w->index] != true)//如果没有访问过,则继续DFS
			DFS(w->index);
		w = w->nextadj;
	}
}

bool Graph::istree()
{
	cout << "深度优先遍历的顺序为:";
	DFS(0);//遍历整个图
	count = count / 2;//除以2为真实边数
	cout<<endl << "该图的边数为:" << count << endl;
	if (count != v - 1)//树的边数应该为N-1
		return false;
	for (int i = 0; i < v; i++)    //即一次dfs没有访问完,此时应该为非连通图,故不是树
		if (visited[i] == false)
			return false;
}

void Graph::create_ver()
{
	cout << "请依序输入图的顶点信息:";
	for (int i = 0; i < v; i++)
	{
		int x;
		cin >> x;
		ver[i].data = x;
		ver[i].firstadj = NULL;
	}
}

//K为顶点编号,length为以该顶点为箭头尾部的边的条数
void Graph::create_edge(int k, int length)
{
	cout << "*****************************************" << endl;
	int x;//需要连接的节点编号
	node2* p = NULL;
	cout << "请输入顶点" << k << "的边信息:" << endl;
	for (int i = 0; i < length; i++)
	{
		if (i == 0)
		{
			cout << "请输入第1条边(编号大于1):";
			cin >> x;
			ver[k - 1].firstadj = new node2;
			ver[k - 1].firstadj->index = x - 1;
			p = ver[k - 1].firstadj;//p指向新建立的节点
		}
		else
		{
			cout << "请输入第" << i + 1 << "条边:";
			cin >> x;
			p->nextadj = new node2;
			p->nextadj->index = x - 1;
			p = p->nextadj;//p指向新建的节点
		}
	}
	cout << "*****************************************" << endl;
}

void Graph::shuchu()
{
	cout << "*****************************************" << endl;
	cout << "您所创建的图为:" << endl;
	cout << "顶点为:" << endl;
	for (int i = 0; i < v; i++)
		cout << ver[i].data << " ";
	cout << endl;
	cout << "邻接链表结构为:" << endl;
	for (int i = 0; i < v; i++)
	{
		cout << ver[i].data;
		node2* p = ver[i].firstadj;
		while (p != NULL)
		{
			cout << "→" << ver[p->index].data;
			p = p->nextadj;
		}
		cout << endl;
	}
	cout << "*****************************************" << endl;
}

int main()
{
	Graph G;
	//创建图
	G.create_ver();
	/*//边数为7的数的创建
	//create_edge的形参一为图顶点的编号,形参2为以该顶点为箭头尾部的边数
	G.create_edge(1, 1);
	G.create_edge(2, 2);
	G.create_edge(3, 4);
	G.create_edge(4, 1);
	G.create_edge(5, 1);
	G.create_edge(6, 1);
	G.create_edge(7, 2);*/

	//边数为6的创建
	G.create_edge(1, 2);
	G.create_edge(2, 3);
	G.create_edge(3, 3);
	G.create_edge(4, 3);
	G.create_edge(5, 3);
	G.create_edge(6, 2);
	//判断是否是树
	
	G.shuchu();
	if (G.istree())
		cout << "改图是树!!!";
	else
		cout << "该图不是树!!!";
	return 0;
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值