图论算法(6)(更新版) --- Tarjan算法求强连通分量

6 篇文章 0 订阅
1 篇文章 0 订阅

在之前的Tarjan算法求连通分量博文中(点此查看),代码实现用到了固定大小数组,扩展起来似乎并不是很方便,在java里这样来实现本身就是不太妥当的,所以下面给出一个更新版本的代码实现:

package test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

public class TarjanSCC<NodeType> {
	int index;
	Map<NodeType, LinkedList<NodeType>> graph;
	Map<NodeType, Integer> indexMap;
	Map<NodeType, Integer> lowLinkMap;
	Stack<NodeType> stack;
	List<List<NodeType>> result;

	public TarjanSCC(Map<NodeType, LinkedList<NodeType>> graph) {
		this.index = 0;
		this.graph = graph;
		this.indexMap = new HashMap<NodeType, Integer>();
		this.lowLinkMap = new HashMap<NodeType, Integer>();
		this.result = new ArrayList<List<NodeType>>();
	}

	public List<List<NodeType>> tarjan() {
		this.index = 0;
		stack = new Stack<NodeType>();
		List<List<NodeType>> result = new ArrayList<List<NodeType>>();
		for (NodeType v : this.graph.keySet()) {
			if (indexMap.get(v) == null) {
				result.addAll(this.strongConnect(v));
			}
		}
		return result;
	}

	public List<NodeType> getSuccessors(NodeType v,Map<NodeType, LinkedList<NodeType>> graph) {
		List<NodeType> successors = new ArrayList<NodeType>();
		Set<NodeType> set = graph.keySet();
		Iterator<NodeType> it = set.iterator();
		while (it.hasNext()) {
			NodeType node = it.next();
			if (node.equals(v)) {
				successors.addAll(graph.get(node));
				break;
			}
		}
		return successors;
	}

	public List<List<NodeType>> strongConnect(NodeType v) {
		indexMap.put(v, index);
		lowLinkMap.put(v, index);
		index++;
		stack.push(v);
		for (NodeType w : getSuccessors(v, graph)) {
			if (indexMap.get(w) == null) {
				strongConnect(w);
				lowLinkMap.put(v, Math.min(lowLinkMap.get(v), lowLinkMap.get(w)));
			} else if (stack.contains(w)) {
				lowLinkMap.put(v, Math.min(lowLinkMap.get(v), indexMap.get(w)));
			}
		}
		if (lowLinkMap.get(v).equals(indexMap.get(v))) {
			List<NodeType> sccList = new ArrayList<NodeType>();
			while (true) {
				NodeType w = stack.pop();
				sccList.add(w);
				if (w.equals(v)) {
					break;
				}
			}
			if (sccList.size() > 1) {
				result.add(sccList);
			}
		}
		return result;
	}
}

下面是主函数调用代码:

package test;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class TestTarjan {
	Map<Integer, LinkedList<Integer>> graph = new HashMap<Integer, LinkedList<Integer>>();
	public TestTarjan(String path) {
		try {
			BufferedReader br = new BufferedReader(new FileReader(path));
			String[] strArray;
			String str;
			while ((str = br.readLine()) != null) {
				strArray = str.split("\\s");
				int a = Integer.parseInt(strArray[0]);
				int b = Integer.parseInt(strArray[1]);
				if (graph.containsKey(a)) {
					graph.get(a).add(b);
				} else {
					LinkedList<Integer> linkedlist = new LinkedList<Integer>();
					linkedlist.add(b);
					graph.put(a, linkedlist);
				}
			}
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public List<List<Integer>> getResult(){
		TarjanSCC<Integer> tarjanScc = new TarjanSCC<Integer>(graph);
		return tarjanScc.tarjan();
	}
	public static void main(String[] args) {
		TestTarjan testTarjan = new TestTarjan("c:/tarjan.txt");
		System.out.println(testTarjan.getResult());
	}
}

这里赋上一组简单的测试数据:

1 2
2 3
3 1
4 2
3 4
3 5
5 6
6 7
7 5
7 8
8 9
9 10
10 8

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值