拓扑算法

拓扑算法

一、用途

拓扑排序应用非常广泛,解决的问题的模型也非常一致。凡是需要通过局部顺序来推导全局顺序的,一般都能用拓扑排序来解决。除此之外,拓扑排序还能检测图中环的存在。

例如:先穿内衣再穿外套,先穿袜子再穿鞋子,先穿内裤再穿裤子。根据局部顺序推导全局顺序为:内衣->外套->袜子->鞋子->内裤->裤子(结果不止一种,因为先穿袜子还是内衣没有顺序)

二、原理

把依赖关系抽象成一个有向图。每个物品对应图中的一个顶点,物品之间的依赖关系就是顶点之间的边。

三、算法

1、Kahn算法(使用邻接表)
从 Kahn 代码中可以看出来,每个顶点被访问了一次,每个边也都被访问了一次,所以,Kahn 算法的时间复杂度就是 O(V+E)(V 表示顶点个数,E 表示边的个数)
示图如下:
在这里插入图片描述关键是inDegree这个变量,统计入度,即该顶点依赖于几个顶点,几个顶点先于它。当它为0的时候就说明该顶点依赖的都已经输出,该点也可以输出了。
如图中的0->1,0先于1,1就是1个入度。
3->4和2->4就说明4有两个依赖,入度为2;

/*
0->1->2->4;0先于1先于2先于4
1->3->4;1先于3先于4
1->5;1先于5
*/
class Graph
{
private:
	int _v;//顶点的个数
	vector<vector<int>*> _adj;
public:
	Graph(int v)
	{
		this->_v = v;
		for (int i = 0; i < v; ++i)
		{
			_adj.push_back(new vector<int>);
		}
	}
	void addEdge(int s, int t)//s先于t,s->t
	{
		_adj[s]->push_back(t);
	}
	void topoSortByKaha()
	{
		int* inDegree = new int[_v] {0};//统计入度,即该顶点依赖于几个顶点,几个顶点先于它。
		for (int i = 0; i < _v; ++i)//遍历图,记录所有顶点的入度
		{
			for (int j = 0; j < (*_adj[i]).size(); ++j)
			{
				int w = (*_adj[i])[j];
				++inDegree[w];
			}
		}
		deque<int> result;
		for (int i = 0; i < _v; ++i)
		{
			if (inDegree[i] == 0)//找到入度为0的顶点,也就是最先输出的顶点
				result.push_back(i);
		}
		while (!result.empty())
		{
			int i = result.at(0);
			result.pop_front();//输出result的第一个点,result中都是入度为0的点
			cout << "->" << i << endl;
			for (int j = 0; j<_adj[i]->size(); ++j)
			{
				int k = (*_adj[i])[j];//找到依赖于刚刚输出的顶点的剩余顶点
				inDegree[k]--;//入度减去1;
				if (inDegree[k] == 0)
				{
					result.push_back(k);//如果恰好有入读为0的就准备输出
				}
			}
		}

	}
};

2、DFS算法(使用逆邻接表)
类似于深度搜索算法,先递归输出依赖的顶点再输出自己。

DFS 算法的时间复杂度我们之前分析过。每个顶点被访问两次,每条边都被访问一次,所以时间复杂度也是 O(V+E)。
在这里插入图片描述

/*
0->1->2->4;0先于1先于2先于4
1->3->4;1先于3先于4
1->5;1先于5
*/
class Graph
{
private:
	int _v;//顶点的个数
	vector<vector<int>*> _adj;
public:
	Graph(int v)
	{
		this->_v = v;
		for (int i = 0; i < v; ++i)
		{
			_adj.push_back(new vector<int>);
		}
	}
	void addEdge(int s, int t)//s先于t,s->t
	{
		_adj[s]->push_back(t);
	}
		void topoSortByKaha()
	{
		int* inDegree = new int[_v] {0};//统计入度,即该顶点依赖于几个顶点,几个顶点先于它。
		for (int i = 0; i < _v; ++i)//遍历图,记录所有顶点的入度
		{
			for (int j = 0; j < (*_adj[i]).size(); ++j)
			{
				int w = (*_adj[i])[j];
				++inDegree[w];
			}
		}
		deque<int> result;
		for (int i = 0; i < _v; ++i)
		{
			if (inDegree[i] == 0)//找到入度为0的顶点,也就是最先输出的顶点
				result.push_back(i);
		}
		while (!result.empty())
		{
			int i = result.at(0);
			result.pop_front();//输出result的第一个点,result中都是入度为0的点
			cout << "->" << i << endl;
			for (int j = 0; j<_adj[i]->size(); ++j)
			{
				int k = (*_adj[i])[j];//找到依赖于刚刚输出的顶点的剩余顶点
				inDegree[k]--;//入度减去1;
				if (inDegree[k] == 0)
				{
					result.push_back(k);//如果恰好有入读为0的就准备输出
				}
			}
		}

	}
	
	void topoSortByDFS()
	{
		//先构建逆邻接表,边s->t表示,s依赖于t,t先于s
		int* inDegree = new int[_v] {0};
		vector<vector<int>*> _inverseAdj;
		for (int i = 0; i < _v; ++i)
		{
			_inverseAdj.push_back(new vector<int>);
		}
		for (int i = 0; i < _v; ++i)//通过领接表,产生逆邻接表,如上图
		{
			for (int j = 0; j<(*_adj[i]).size(); ++j)
			{
				int w = (*_adj[i])[j];
				_inverseAdj[w]->push_back(i);
			}
		}
		bool* visited = new bool[_v] {0};//关键表示顶点是否被访问过
		for (int i = 0; i<_v; ++i)
		{
			if (visited[i] == false)//未被访问的顶点进行访问
			{
				visited[i] = true;
				dfs(i, _inverseAdj, visited);
			}
		}
	}
	void dfs(int vertex, vector<vector<int>*>& _inverseAdj, bool visited[])
	{
		for (int i = 0; i<_inverseAdj[vertex]->size(); ++i)
		{
			int w = (*_inverseAdj[vertex])[i];
			if (visited[w] == true)//表示当前顶点依赖的点已经输出了
			//如1->0,因为0之前已经输出,所以这里直接continue
			{
				continue;
			}
			visited[w] = true;
			dfs(w, _inverseAdj, visited);//递归访问当前顶点依赖的顶点,访问它的依赖关系。
		}
		cout << "->" << vertex << endl;
	}

};
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
RNG(Relative Neighborhood Graph)是一种基于距离的图形拓扑结构,它在无线传感器网络中被广泛应用。下面是使用 MATLAB 实现 RNG 拓扑算法的简单步骤: 1. 定义传感器节点坐标和通信范围,生成邻接矩阵。 ```matlab n = 50; % 传感器节点数目 r = 0.2; % 通信范围 pos = rand(n,2); % 生成随机节点坐标 adj_mat = zeros(n); % 初始化邻接矩阵 for i = 1:n for j = i+1:n dist = norm(pos(i,:)-pos(j,:)); % 计算节点之间距离 if dist < r % 如果距离小于通信范围,则两个节点之间有边 adj_mat(i,j) = 1; adj_mat(j,i) = 1; end end end ``` 2. 根据邻接矩阵生成 RNG 拓扑结构。 ```matlab rng_adj_mat = zeros(n); % 初始化 RNG 邻接矩阵 for i = 1:n for j = i+1:n if adj_mat(i,j) == 1 % 如果节点 i 和节点 j 有边 flag = true; for k = 1:n if adj_mat(i,k) == 1 && adj_mat(j,k) == 1 && i ~= k && j ~= k % 如果节点 i 和节点 j 都与节点 k 相邻 flag = false; % 则节点 i 和节点 j 不是 RNG 图中的边 break; end end if flag % 如果节点 i 和节点 j 是 RNG 图中的边 rng_adj_mat(i,j) = 1; rng_adj_mat(j,i) = 1; end end end end ``` 3. 可视化 RNG 拓扑结构。 ```matlab gplot(rng_adj_mat,pos,'-*'); % 用节点坐标和邻接矩阵可视化 RNG 图 title('RNG Topology'); ``` 完整代码如下: ```matlab n = 50; % 传感器节点数目 r = 0.2; % 通信范围 pos = rand(n,2); % 生成随机节点坐标 adj_mat = zeros(n); % 初始化邻接矩阵 for i = 1:n for j = i+1:n dist = norm(pos(i,:)-pos(j,:)); % 计算节点之间距离 if dist < r % 如果距离小于通信范围,则两个节点之间有边 adj_mat(i,j) = 1; adj_mat(j,i) = 1; end end end rng_adj_mat = zeros(n); % 初始化 RNG 邻接矩阵 for i = 1:n for j = i+1:n if adj_mat(i,j) == 1 % 如果节点 i 和节点 j 有边 flag = true; for k = 1:n if adj_mat(i,k) == 1 && adj_mat(j,k) == 1 && i ~= k && j ~= k % 如果节点 i 和节点 j 都与节点 k 相邻 flag = false; % 则节点 i 和节点 j 不是 RNG 图中的边 break; end end if flag % 如果节点 i 和节点 j 是 RNG 图中的边 rng_adj_mat(i,j) = 1; rng_adj_mat(j,i) = 1; end end end end gplot(rng_adj_mat,pos,'-*'); % 用节点坐标和邻接矩阵可视化 RNG 图 title('RNG Topology'); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值