c++生成随机平面无向连通图

本文介绍了如何使用C++随机生成平面无向连通图,通过生成最小连通子图保证图的连通性,并赋予节点二维坐标确保平面性。算法通过避免边交叉来实现随机性,存储图结构使用NodeArray和EdgeArray。文章提供关键代码段,并展示不同节点数量下的运行结果,最后通过MATLAB绘制生成的图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

c++生成随机平面无向连通图


前言为了检验路径搜索算法的优劣,需要用大量的图的数据来运行对应的算法,例如深度优先搜搜、宽度优先搜索、迪杰斯特拉算法等等,而对于大多数实际问题,例如搜索最短路径的问题,其问题空间本身是一种特殊的图——平面无向图,无向图的定义相信大家都明白,所谓“平面”,即如果以一个合适的角度将图中的所有节点和边投影到一个平面上,不能有两条及以上数量的边相互交叉。
如果能随机生成平面无向图,我们就可以用其来对各种搜索算法进行测试。基于此需求,本人想出了一个随机生成平面无向图的算法,并加以实现。

代码(已经上传至码云):随机生成平面无向图

算法描述

图——可以简单的理解为节点集合和边集合,想一想,如果想要随机生成平面无向图,我们需要保证什么?
我们需要确保三点:图的连通性、图为平面图、图的生成是具有一定随机的
对于连通性,我们需要先生成图的最小连通子图,从而保证图的连通性;对于图的“平面性”,我们可以赋予节点一个二维坐标(x,y),从而保证所有的节点都在一个平面上,对于图的“随机性”,我们可以在生成节点坐标时,随机的确定其(x,y)的具体值。
在这里,需要明确一点的是“对于一个图来说,其极小连通子图一定是平面图”,这点可以用反证法来证明,如果极小连通子图不是平面图,则至少会存在一个类似多面体的结构,比如四面体,这样的话就与极小连通子图的性质相悖了!
经过上述的分析,我们有了初步的算法思路:
(1)根据节点数量生成随机的极小连通子图;生成的极小连通子图时,给每个节点都赋予一个坐标(x,y),坐标中的x、y的值是具有随机性的,并保证节点之间的边(在这里就是线段)不交叉;
(2)添加剩余的边,同时保证添加的边与现存的边不会相交,直到添加完所有的边。
为了存储生成的图,我们用了两个数组来分别存储节点的信息和边的信息:NodeArray[NodeCounts]和EdgeArray[EdgeCounts]。
算法的具体描述如下:

输入:节点个数N、边的个数M、边的长度范围;
输出:节点数组NodeArray[],边数组EdgeArray[]
准备工作:新建节点类Node和边类Edge,Node类的数据为节点的x坐标、y坐标和节点的编号,Edge类的数据为边两端的节点node1和node2.
具体步骤:
(1)生成1-N的随机序列Random[];
(2)顺序的遍历随机序列,从中拿出Random[i]作为新节点NewNode的编号ID(编号从1-N);
(3)如果新节点NewNode是第一个确定编号的点,将其坐标置为(0,0);如果不是,则从已经确定了坐标的旧节点中随机挑选一个OldNode来与NewNode进行“配对”,并随机确定NewNode的坐标(x,y),生成新边NewEdge(NewNode,OldNode);
(4)检验新边NewEdge(NewNode,OldNode)是否有效,如果无效,则通过随机生成NewNode的坐标(x,y)更新新边NewEdge,具体约束条件为:a.NewEdge(NewNode,OldNode)的长度在输入的边的范围内;b.NewEdge(NewNode,OldNode)必须保证与已经存在的边不能有交点(除了OldNode的其它边);c.NewNode的坐标不能在已有的边上(即点在线段上);
(5)如果NewEdge(NewNode,OldNode)有效,则将NewNode添加进节点数组NodeArray[]中,将NewEdge添加到边数组EdgeArray[]中,然后返回(3)继续生成新边;
(6)当所有的节点都确定坐标后,就生成了最小连通子树,此时确定了(N-1)条边,接下来再随机添加两个节点之间的边,总数为(M-(N-1)),这里的边也得保证与已经存在的边不能有交点(除了其两个节点的其它边);
(7)当M条边都添加完了之后,输出结果;

关键代码

工具:VS2017
代码(已经上传至码云):随机生成平面无向图
节点与边用容器存储:

vector<Node> NodeArray;
vector<Edge> EdgeArray;
//************************************
// Method:    CreatPlaneUndirectedGraph
// FullName:  CreatPlaneUndirectedGraph
// Access:    public 
// Returns:   void
// Qualifier:生成平面连通无向图
// Parameter: int NodeCounts 节点数量
// Parameter: int EdgeCounts 边的数量
// Parameter: int EdgeMaxLen 边的最大值
// Parameter: int EdgeMinLen 边的最小值
//************************************
void CreatPlaneUndirectedGraph(int NodeCounts, int EdgeCounts, int EdgeMaxLen, int EdgeMinLen)
{
   
//先生成最小平面连通无向图
	//生成一个随机序列
	int *randomArray = new int[NodeCounts];
	RandomArray(randomArray,NodeCounts);
	srand(time(NULL));
	//顺序的遍历随机序列,添加边
	for (int i = 0; i < NodeCounts; ++i)
	{
   
		int Node_id = randomArray[i];
		//如果是第一个,设置其坐标为(0,0)
		if (i == 0)
		{
   
			Node new_node(0,0, Node_id);
			NodeArray.push_back(new_node);
		}
		//否则,随机确定其坐标
		else
		{
   
			//从已经确定坐标的点中,随机挑选一个出来作为连接节点
			int val = rand() % i;
			Node choose_node= NodeArray.at(val);
			//产生符合要求的新节点
			Node new_node(0,0, Node_id);
			CreatNewNodeX_Y(new_node,choose_node,EdgeMaxLen,EdgeMinLen);
			//将边和节点添加进容器中
			Edge new_edge(choose_node,new_node);
			EdgeArray.push_back(new_edge);
			NodeArray.push_back(new_node);
			
		}
	}
//再添加剩余的边
	while (EdgeArray.size() < EdgeCounts)
	{
   
		int node1_id=0, node2_id=0;
		while (node1_id == node2_id)
		{
   
			//RandomCreatFunc(1, NodeArray.size());
			node1_id = rand() % NodeArray.size();
			node2_id = rand() % NodeArray.size();
		}
		Node choose_node1=NodeArray.at(node1_id);
		Node choose_node2= NodeArray.at(node2_id);
		if (IsNodeConnected(choose_node1, choose_node2) == false)
		{
   
			Edge newEdge(choose_node1, choose_node2);
			if (IsEdgeIntersectedEdgeArray(newEdge) == false)
				EdgeArray.push_back(newEdge);
		}
	
	}
}

辅助函数为:

int max(int x,int y)
{
   
	return x > y ? x : y;
}
int min(int x, int y)
{
   
	return x > y ? y : x;
}
double mult(Node a, Node b, Node c)
{
   
	return (a.GetX() - c.GetX())*(b.GetY() - c.GetY()) - 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值