流图中的强联通分量

在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。

  网上关于强联通分量的理论与分析十分的多,这里不再赘述。

  强联通分量在循环子结构的识别中尤其的重要,对于一个自然循环(可规约),我们尚可通过迭代的方法找到循环中所有的块,但是对于不可规约流图,自然就不是这么简单的了。对于这种图,一种方法是寻找图的强联调分量。

  Tarjan算法实现:


	template<typename BBTy>
	class SCCDiscovery{
	public:
		using scc_set = set<BBTy*>;

	private:

		unordered_map<BBTy*, unsigned> Dfn;
		unordered_map<BBTy*, unsigned> LowLink;

		vector<BBTy*> NodeStack;

		unsigned DfnIndex = 1;

		unordered_map<BBTy*, scc_set> SCCs;

		// Tarjan
		void findStrongComponent(BBTy* root) {

			Dfn[root] = ++DfnIndex;
			LowLink[root] = DfnIndex;
			NodeStack.push_back(root);

			for (auto i:llvm::make_range(succ_begin(root),succ_end(root))) {
				// 未被遍历过,进行向后遍历
				// 并在遍历完成后,更新当前节点的lowlink
				if (Dfn[i] == 0) {
					findStrongComponent(i);
					LowLink[root] = min(LowLink[i], LowLink[root]);
				}
				// 如果已经遍历过了,并且dfs序小于当前节点,并且这个节点还在栈中
				// 则进一步更新当前节点
				else if (Dfn[i] < Dfn[root] &&
					(find(NodeStack.begin(), NodeStack.end(), i) != NodeStack.end())) {
					LowLink[root] = min(LowLink[root], Dfn[i]);
				}
			}

			// 如果回边指向当前节点或者是单个节点
			if (LowLink[root] == Dfn[root]) {
				scc_set allNodeInSCC;

				// 将所有属于当前连通分量的节点放入到容器中
				while (NodeStack.size()) {
					auto top = NodeStack.back();
					if (Dfn[top] < Dfn[root]) {
						SCCs[root] = allNodeInSCC;
						return;
					}
					NodeStack.pop_back();
					allNodeInSCC.insert(top);
				}
				// 整个CFG是一个大连通分量的情况
				SCCs[root] = allNodeInSCC;
			}
		}

	public:

		void calculate(BBTy* entry) {

			findStrongComponent(entry);
		}

		scc_set getSccByHeader(BBTy* bb) {
			return SCCs[bb];
		}

	};

  流图一般是单入口的,所以这里没有去处理不可达节点的情况。

参考资料:

  1. 高级编译器设计与实现。

(由于博主水平有限,如有讲述错误之处,请留言指正。)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值