java面试---图的最小路径

无权重

在查找最小路径上,图的题目特别多,无权重的情况,找最小路径就是图的广度优先遍历。广度优先遍历就是依靠队列来实现。由于比较简单,这里不贴代码了。

为什么是广度优先

图的遍历有深度和广度两种,那么为什么使用广度去找出最小路径呢。其实他成立的条件是无权重,就是每条路径的消费都是一样的。广度优先遍历对应的树的层次遍历,这样就更好理解了,树的层次遍历,由于是一层一层的看,那么层数最小的情况就是最短的情况。

无负权重

无负权重的情况下,迪杰斯特拉是个不错的选择。 迪杰斯特拉是大学算法课上基本都讲的内容。其实算法思想还好,写起来稍微繁琐一些。

算法讲解

迪杰斯特拉的重点就是对一个图标的填充。

迪杰斯特拉

接下来我们来具体结合一个例子来说明这个表格如何填充 输入图片说明

如上图,起点为a,终点是f。

初始化表格

我们先初始化表格,因为a是起点,所以没有包含在内计算。这个计算其实就是把起点相关的初始化到表格里。b是可达的,其余节点都是不可达的,所以花费默认都是没有。

节点花费是否访问
b2-
c--
d--
e--
f--

查找最小消耗的节点

根据上图,最小消耗的就是b

继续访问节点

b就当做被访问过了,b到c是4,所以c的花费就是6,然后类推其他f,d,e

节点花费是否访问
b2
c6-
d3-
e--
f7-

重复的步骤

  1. 找出最小没有访问的节点
  2. 访问节点的邻居节点
  3. 更新图表,保存消耗最小的值

结果

节点花费是否访问
b2
c6
d3
e6
f7

终点是f,结果就是7

画出路径

上面的情况只是找出了最小消耗,想找出路径,修改表格就好,保存对应的父节点

代码实现


public class Dijkstra {

	public static void main(String[] args) {
		String[] startEnd = new String[2];
		Map<String, Node> initData = initData(startEnd);
		Set<String> process = new HashSet<>();
		Map<String, NodeCost> costList = new HashMap<>();

		init(initData, costList, startEnd[0]);
		find(initData, process, costList);

		NodeCost nodeCost = costList.get(startEnd[1]);
		LinkedList<String> list = new LinkedList<>();
		System.out.println(nodeCost.cost);
		list.addFirst(nodeCost.current);
		while (nodeCost != null) {

			list.addFirst(nodeCost.parent);
			nodeCost = costList.get(nodeCost.parent);
		}
		System.out.println(list);

	}

	
	public static void find(Map<String, Node> initData, Set<String> process, Map<String, NodeCost> costList) {
		NodeCost minNode = getMinNode(process, costList);
		while (minNode != null) {
			Node node = initData.get(minNode.current);
			Map<String, Integer> nextNode = node.nextNode;
			Iterator<Entry<String, Integer>> iterator = nextNode.entrySet().iterator();
			while (iterator.hasNext()) {
				Entry<String, Integer> next = iterator.next();
				int cost = minNode.cost + next.getValue();
				NodeCost nodeCost = costList.get(next.getKey());
				int oldCost = nodeCost.cost;
				if (oldCost > cost) {
					nodeCost.parent = node.name;
					nodeCost.cost = cost;
				}
			}
			process.add(node.name);
			minNode = getMinNode(process, costList);

		}

	}

	
	//找出最小消耗没有访问过的节点
	public static NodeCost getMinNode(Set<String> process, Map<String, NodeCost> costList) {

		Collection<NodeCost> values = costList.values();
		NodeCost preCost = null;

		for (NodeCost cost : values) {
			if (!process.contains(cost.current)) {
				if (preCost == null) {
					preCost = cost;
				} else if (preCost.cost >= cost.cost) {
					preCost = cost;
				}
			}

		}

		return preCost;
	}

	
	//初始化图表耗费
	public static void init(Map<String, Node> initData, Map<String, NodeCost> costList, String start) {
		Collection<Node> values = initData.values();
		Iterator<Node> iteratorValues = values.iterator();
		while (iteratorValues.hasNext()) {

			Node node = iteratorValues.next();
			Map<String, Integer> nextNode = node.nextNode;
			Iterator<Entry<String, Integer>> iterator = nextNode.entrySet().iterator();
			while (iterator.hasNext()) {
				Entry<String, Integer> next = iterator.next();
				NodeCost cost = new NodeCost();
				cost.parent = node.name;
				cost.current = next.getKey();
				if (node.name.equals(start)) {
					cost.cost = next.getValue();
				} else {
					cost.cost = Integer.MAX_VALUE;
				}
				NodeCost oldCost = costList.get(next.getKey());
				if (oldCost == null || oldCost.cost == Integer.MAX_VALUE) {
					costList.put(next.getKey(), cost);
				}

			}
		}

	}

	
	//初始化图结构
	public static Map<String, Node> initData(String[] startEnd) {
		Map<String, Node> node = new HashMap<>();

		Node a = new Node();
		a.name = "a";
		a.nextNode = new HashMap<String, Integer>() {
			{
				put("b", 5);
				put("f", 2);
			}

		};

		node.put("a", a);

		Node b = new Node();
		b.name = "b";
		b.nextNode = new HashMap<String, Integer>() {
			{
				put("c", 4);
				put("e", 2);
			}

		};
		node.put("b", b);

		Node c = new Node();
		c.name = "c";
		c.nextNode = new HashMap<String, Integer>() {
			{
				put("d", 3);
				put("e", 6);
			}

		};
		node.put("c", c);

		Node d = new Node();
		d.name = "d";

		node.put("d", d);

		Node e = new Node();
		e.name = "e";
		e.nextNode = new HashMap<String, Integer>() {
			{

				put("d", 1);
			}

		};
		node.put("e", e);

		Node f = new Node();
		f.name = "f";
		f.nextNode = new HashMap<String, Integer>() {
			{

				put("b", 8);
				put("e", 7);
			}

		};
		node.put("f", f);

		startEnd[0] = "a";
		startEnd[1] = "d";

		return node;
	}

}


//图表的结构
class NodeCost {
	String current;
	String parent;
	Integer cost;

	public String getCurrent() {
		return current;
	}

	public void setCurrent(String current) {
		this.current = current;
	}

	public String getParent() {
		return parent;
	}

	public void setParent(String parent) {
		this.parent = parent;
	}

	public int getCost() {
		return cost;
	}

	public void setCost(int cost) {
		this.cost = cost;
	}

	@Override
	public String toString() {
		return "NodeCost [current=" + current + ", parent=" + parent + ", cost=" + cost + "]";
	}

}

//原始数据结构
class Node {
	String name;
	Map<String, Integer> nextNode = new HashMap<>();

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Map<String, Integer> getNextNode() {
		return nextNode;
	}

	public void setNextNode(Map<String, Integer> nextNode) {
		this.nextNode = nextNode;
	}

}

这里代码挺多,但是大部分都是去初始化图的结构了,真正的操作胆码数量还是可以查看的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值