图的构造、深度和广度遍历、拓扑排序、最小生成树prim和Kruskal算法(java实现)

图构造与相关算法

图的实现

import java.util.ArrayList;
/*
 * 点
 */
public class Node {
	public int value; //值
	public int in; //入度
	public int out; //出度
	public ArrayList<Node> nexts;
	public ArrayList<Edge> edges;
	
	public Node(int value) {
		this.value = value;
		in = 0;
		out = 0;
		nexts = new ArrayList<>();
		edges = new ArrayList<>();
	}
}

/*
 * 边
 */
public class Edge {
	public int weight; //权重
	public Node from; 
	public Node to;
	
	public Edge(int weight,Node from,Node to) {
		this.weight = weight;
		this.from = from;
		this.to = to;
	}
}
import java.util.HashMap;
import java.util.HashSet;
/*
 * 图
 */
public class Graph {
	public HashMap<Integer,Node> nodes; 
	public HashSet<Edge> edges;
	
	public Graph() {
		nodes = new HashMap<>();
		edges = new HashSet<>();
	}
	
}

图的遍历

import java.util.HashSet;
import java.util.Stack;

public class Dfs {
	//从Node出发,深度优先遍历
	public static void bfs(Node node) {
		if(node == null) {
			return;
		}
		Stack<Node> stack = new Stack<>();
		HashSet<Node> set = new HashSet<>();
		stack.add(node);
		set.add(node);
		System.out.println(node.value);
		while(!stack.isEmpty()) {
			Node cur = stack.pop();
			for(Node next:cur.nexts) {
				if(!set.contains(next)) {
					stack.push(cur);
					stack.push(next);
					set.add(next);
					System.out.println(next.value);
					break;
				}
			}
		}
	}
}
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;

public class Bfs {
	// 从node出发,广度优先遍历
	public static void bfs(Node node) {
		if(node == null) {
			return;
		}
		Queue<Node> queue = new LinkedList<>();
		HashSet<Node> set = new HashSet<>();
		queue.add(node);
		set.add(node);
		while(!queue.isEmpty()) {
			Node cur = queue.poll();
			System.out.println(cur.value);
			for(Node next:cur.nexts) {
				if(!set.contains(next)) {
					set.add(next);
					queue.add(next);
				}
			}
		}
	}
}

图的拓扑排序

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class SortedTopology {
	/*
	   *   拓扑排序
	 */
	public static List<Node> sortedTopology(Graph graph){
		// key : 某一个node
		// value : 剩余的入度
		HashMap<Node,Integer> inMap = new HashMap<>();
		// :剩余入度为0的点,才能进这个队列
		Queue<Node> zeroInQueue = new LinkedList<>();
		for(Node node:graph.nodes.values()) {
			inMap.put(node, node.in);
			if(node.in==0) {
				zeroInQueue.add(node);
			}
		}
		// :拓扑排序的结果,依次加入result
		List<Node> result = new ArrayList<>();
		
		while(!zeroInQueue.isEmpty()) {
			Node cur = zeroInQueue.poll();
			result.add(cur);
			for(Node next:cur.nexts) {
				inMap.put(next, inMap.get(next)-1);
				if(inMap.get(next)==0) {
					zeroInQueue.add(next);
				}
			}
		}
		return result;
	}
}

图的最小生成树

import java.util.Comparator;
import java.util.HashSet;
import java.util.PriorityQueue;
import java.util.Set;
/*
 * prim算法实现最小生成树
 */
public class Prim {
	
	public static class EdgeComparator implements Comparator<Edge> {
		public int compare(Edge e1,Edge e2) {
			return e1.weight - e2.weight;
		}
	}
		
	public static Set<Edge> PrimMST(Graph graph) {
		//	解锁的边进入小根堆
		PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new EdgeComparator());
		//	哪些点被解锁出来了
		HashSet<Node> nodeSet = new HashSet<>();
		//	标记重复边
		HashSet<Edge> edgeSet = new HashSet<>();
		//	将需要的边添加到result里
		Set<Edge> result = new HashSet<>();
		
		
		for(Node node : graph.nodes.values()) { //	防止森林
			if(!nodeSet.contains(node)) {
				nodeSet.add(node);
				for(Edge edge : node.edges) { //	由一个点解锁所有的边
					if(!edgeSet.contains(edge)) {
						edgeSet.add(edge);
						priorityQueue.add(edge);
					}
				}
				while(!priorityQueue.isEmpty()) { 
					Edge edge = priorityQueue.poll();//从队列中弹出一个最小的边
					Node toNode = edge.to; //	可能的一个新的点
					if(!nodeSet.contains(toNode)) {//toNode如果不在,就加进来
						nodeSet.add(toNode);
						result.add(edge);
						for(Edge nextEdge : toNode.edges) //将toNode的所有边加入队列
							if(!edgeSet.contains(nextEdge)) {
								edgeSet.add(nextEdge);
								priorityQueue.add(nextEdge);
							}
					}
				}
			}
		}
		return result;
	}
}
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.Stack;

/*
 * 	利用并查集和Kruskal算法实现最小生成树(如果是无向图返回的是单侧的边集,另一侧需要手动添加)
 */
public class UnionFindAndKruskal {
	
	public static class UnionFind{
		//	key 某一个节点,value key节点往上的节点
		private HashMap<Node,Node> fatherMap;
		//  key 某一个集合的代表节点,value key所有集合的节点个数
		private HashMap<Node,Integer> sizeMap;
		
		public UnionFind() {
			fatherMap = new HashMap<Node,Node>();
			sizeMap = new HashMap<Node,Integer>();
		}
		
		public void makeSets(Collection<Node> nodes) {
			fatherMap.clear();
			sizeMap.clear();
			for(Node node:nodes) {
				fatherMap.put(node,node);
				sizeMap.put(node, 1);
			}
		} 
		
		private Node findFather(Node n) {
			Stack<Node> path = new Stack<>();
			while(n!=fatherMap.get(n)) {
				path.add(n);
				n = fatherMap.get(n);
			}
			while(!path.isEmpty()) {
				fatherMap.put(path.pop(), n);
			}
			return n;
		}
		
		public boolean isSameSet(Node a,Node b) {
			return findFather(a) == findFather(b);
		}
		
		public void union(Node a,Node b) {
			if(a==null||b==null) {
				return;
			}
			Node aDai = findFather(a);
			Node bDai = findFather(b);
			if(aDai != bDai) {
				int aSetSize = sizeMap.get(aDai);
				int bSetSize = sizeMap.get(bDai);
				if(aSetSize <= bSetSize) {
					fatherMap.put(aDai, bDai);
					sizeMap.put(bDai, aSetSize + bSetSize);
					sizeMap.remove(aDai);
				}else {
					fatherMap.put(bDai, aDai);
					sizeMap.put(aDai, aSetSize + bSetSize);
					sizeMap.remove(bDai);
				}
			}
		}
	}
	
	public static class EdgeComparator implements Comparator<Edge>{
		@Override
		public int compare(Edge o1,Edge o2) {
			return o1.weight-o2.weight;
		}
	}
	
	public static Set<Edge> kruskalMST(Graph graph){
		UnionFind unionFind = new UnionFind();
		unionFind.makeSets(graph.nodes.values());
		PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new EdgeComparator());
		
		for(Edge edge:graph.edges) { // M条边
			priorityQueue.add(edge);  // O(logM) 
		}
		Set<Edge> result = new HashSet<>();
		while(!priorityQueue.isEmpty()) { // M 条边
			Edge edge = priorityQueue.poll(); // O(logM)
			if(!unionFind.isSameSet(edge.from, edge.to)) { // O(1)
				result.add(edge);
				unionFind.union(edge.from, edge.to);
			}
		}
		return result;
	}
	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杜柠函

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值