每日练习之图

自定义转换接口

由于图结构的定义灵活多变,不可能每次遇到一个新的形式再去思考如何解题,所以我们需要一个接口,将所有的形式的图转变为我们熟悉的形式。

//图
public class Graph {
	//点集
	public HashMap<Integer,Node> nodes;
	//边集
	public HashSet<Edge> edges;
	public Graph() {
		this.nodes=new HashMap<Integer,Node>();
		this.edges=new HashSet<Edge>();
	}	
}
//点
public class Node {
	public int value;
	public int in;//入度
	public int out;//出度
	public ArrayList<Node> nexts=new ArrayList();//相邻点
	public ArrayList<Edge> edges=new ArrayList();//属于的边
	public Node(int value, int in, int out) {
		super();
		this.value = value;
		this.in = in;
		this.out = out;
	}
	public Node(int value) {
		super();
		this.value = value;
	}
	
}
//边
public class Edge {
	public Node from;
	public Node to;
	public int weight;//权重
	public Edge(Node from, Node to, int weight) {
		super();
		this.from = from;
		this.to = to;
		this.weight = weight;
	}
	
}
//装换
public class CreateGraph {
	public static Graph createGraph(Integer[][] matrix) {
		Graph graph=new Graph();
		//对矩阵进行转化
		for(int i=0;i<matrix.length;i++) {//[i][0]——from节点,[i][1]——to节点,[i][3]——权重
			int fromNode=matrix[i][0];
			int toNode=matrix[i][1];
			int weight=matrix[i][2];
			//判断图的点集中是否已有此节点
			if(!graph.nodes.containsKey(fromNode)) {
				graph.nodes.put(fromNode, new Node(fromNode));
			}
			//判断图的点集中是否已有此节点
			if(!graph.nodes.containsKey(toNode)) {
				graph.nodes.put(toNode,new Node(toNode));
			}
			//图中无,可以进行添加节点,并设置节点值
			Node fNode=graph.nodes.get(fromNode);
			Node tNode=graph.nodes.get(toNode);
			fNode.out=fNode.out++;
			fNode.nexts.add(tNode);
			
			tNode.in=tNode.in++;
			tNode.nexts.add(fNode);
			//添加边集
			Edge edge=new Edge(fNode,tNode,weight);
			graph.edges.add(edge);
		}
		return graph;
	}
}
图宽度优先算法

图中每个点多有相邻点,对一个点操作后需要引入下一个点,这样可能会再次对操作过的点又进行操作。所以我们需要一个界定条件。使用set集合作为界定条件,对一个点操作后将它放入set集合中,如果set集合中出现这个点说明已经操作过,不需要在操作。使用队列queue结构实现宽度优先算法。

//宽度优先算法
public class Bfs {
	public static void travleGraph_bfs(Node node) {
		if(node==null) {
			System.out.println("空图");
			return;
		}
		Queue<Node> queue=new LinkedList();
		HashSet<Node> isExist=new HashSet();
		queue.add(node);
		isExist.add(node);
		while(!queue.isEmpty()) {
			Node curNode=queue.poll();
			System.out.print(curNode.value+" ");
			//邻接点入队
			for(Node next:curNode.nexts) {
				//判断邻接点是否已经入队过
				if(!isExist.contains(next)) {
					queue.add(next);
					isExist.add(next);
				}
			}
		}
	}
}
图的深度优先算法

当每到一个点,我们就取这个点的相邻节点中的一个点,对这个节点的相邻点继续取它的相邻点一直取到低,其中有两个问题:①如果有循环,会一直循环下去②相邻点有多个,遍历完一个,如果再走另一个
解决:
①需要一个界定条件,使用set集合作为界定条件。遍历一个就放入set集合。
②使用栈去存储节点,当我们弹出节点时判断它的相邻节点是否存在如果存在,就将弹出的节点重新压回去在将它的相邻节点压入。这个就保持了节点的状态,下次还能遍历到它的其他相邻节点。

public class Dfs {
	public static void travleGraph_bfs(Node node) {
		if(node==null) {
			System.out.println("空图");
			return;
		}
		Stack<Node> stack=new Stack();
		HashSet<Node> set=new HashSet();//界定条件
		stack.push(node);
		set.add(node);
		System.out.print(node.value+" ");
		while(!stack.isEmpty()) {
			Node curNode=stack.pop();
			//遍历邻点
			for(Node next:curNode.nexts) {
				//判断是否遍历过此点
				if(!set.contains(next)) {
					stack.push(curNode);//重新入栈
					stack.push(next);//邻点入栈
					set.add(next);//表示邻点已经遍历过
					System.out.print(next.value+" ");
					break;
				}
			}
		}
	}
}
图的拓扑排序

拓扑结构简单理解为,前一个条件完成后下一个条件才可进行。
在这里插入图片描述
实现思路:每个节点都有入度与出度,可以从这个方向入手实现,使用队列结构对节点进行操作。

public class TopologySort {
	public static List<Node> sortedTopology(List<Node> nodes){
		if(nodes.isEmpty()) {
			System.out.println("空图");
			return nodes;
		}
		Queue<Node> queue=new LinkedList();
		ArrayList<Node> list=new ArrayList();
		//寻找list中第一批入度为0的点,对这些点入队
		for(Node node:nodes) {
			if(node.in==0) {
				queue.add(node);
			}
		}
		while(!queue.isEmpty()) {
			Node curNode=queue.poll();
			list.add(curNode);//将出队的节点入列表
			curNode.out--;//对此节点出度减一
			System.out.print(curNode.value+" ");
			//寻找出队点的下一个点
			for(Node next:curNode.nexts) {
				next.in--;//将寻找到的点入度减一
				//判断这些邻点有没有入度为0的
				if(next.in==0) {
					queue.add(next);
				}
			}
		}
		return list;
	}
}

//寻找出队点的下一个点
			for(Node next:curNode.nexts) {
				next.in--;//将寻找到的点入度减一
				//判断这些邻点有没有入度为0的
				if(next.in==0) {
					queue.add(next);
				}
			}
		}
		return list;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值