Dijkstra算法(迪杰斯特)——有权无权通用(原创)

/**
 * @author shany
 * @date 2018年8月27日 上午8:50:12 
 * @version V1.0  
 */
package shany;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class DjstSF {

	// 设置当前图的形式(有权图,无权图),默认为无权图false
	static boolean direction = false;
	// 存储所有的节点
	static List<String> all_list = new ArrayList<>();
	// 存储所有路径和之间的距离
	static Map<String, Integer> data_map = new HashMap<String, Integer>();
	// 当前记录的路径和权值
	static Map<String, Integer> use_map = new HashMap<>();
	// 开始节点
	static String start_seat;
	// 结束节点
	static String end_seat;

	// 用于测试
	// static int num = 0;

	// 有权无权图都适用
	public void addNum(String key) {
		// 判断传入的key是否为空
		key = key == null ? start_seat : key == "" ? start_seat : key;
		Set<String> set = data_map.keySet();
		// 新的value应该加上的值
		int date = use_map.containsKey(key) ? use_map.get(key) : 0;
		// 获取key的末尾节点值
		String key_sta = key.indexOf("-") != -1 ? key.substring(
				key.lastIndexOf("-") + 1, key.length()) : key;
		// 循环遍历data_map里面的值
		for (String str : set) {
			// 先获取对应value值
			int val = data_map.get(str);
			// 以下三行用于测试
			// System.out.println("——————————");
			// System.out.println("第" + ++num + "次:");
			// System.out.println("key=" + key + "    " + "str=" + str + "  --"+
			// val);
			String ss[] = str.split("-");
			// 判断传入的key中是否包含ss[1]
			if (!(new ArrayList<String>(Arrays.asList(key.split("-")))
					.contains(ss[1]))) {
				// 如果是有权图,且ss[0]和key的尾部对应
				if (direction && ss[0].equals(key_sta)) {
					// System.out.println("youquan: str=" + str);//用于测试
					use_map.put(add_new_key(key, str), date + val);// 将新key和value插入到use_map中
					use_map.remove(key);// 当有新key插入时,就可以删除老key了,重复删除不会有异常
				} else if (!direction
						&& (ss[0].equals(key_sta) || ss[1].equals(key_sta))) {
					// 无权图要对ss[0]和ss[1]同时判断,同时key==初始点要做额外判断
					if (key == start_seat
							|| !(new ArrayList<String>(Arrays.asList(key
									.split("-"))).contains(ss[0]))) {
						// System.out.println("wuquan: str=" + str);//用于测试
						use_map.put(add_new_key(key, str), date + val);
						use_map.remove(key);// 当有新key插入时,就可以删除老key了,重复删除不会有异常
					}
				}
				// System.out.println("第" + ++num + "次:");//用于测试
				// input_map(); //用于测试
			}
		}
	}

	// 对老的key,和新加入的key进行组合,输出新的要插入的key。
	public String add_new_key(String old_key, String ext) {
		if (old_key.indexOf(ext.split("-")[0]) != -1)
			return old_key + "-" + ext.split("-")[1];
		else if (old_key.indexOf(ext.split("-")[1]) != -1)
			return old_key + "-" + ext.split("-")[0];
		// 用于use_map传入到addNum的key为null(这个主要防止出现意外错误)时
		return old_key + "-" + ext;

	}

	// 测试时输出use_map的遍历,用于观察(测试、观察用)
	public void input_map() {
		for (Map.Entry<String, Integer> entry : use_map.entrySet()) {
			String key = entry.getKey().toString();
			System.out.println("key:" + key + "  ——" + use_map.get(key));
		}
	}

	// 循环这个路线
	public void roll_map() {
		// 记录改变的key数量
		int sure_end = 0;
		Map<String, Integer> temp_map = new HashMap<String, Integer>();
		temp_map.putAll(use_map);
		// 第一次use_map为null时调用此if
		if (temp_map == null || temp_map.size() == 0) {
			// System.out.println("roll_map:null");
			addNum(null);
			sure_end++;
		} else {
			// 是否全部走完,防止死循环
			for (Map.Entry<String, Integer> entry : temp_map.entrySet()) {
				String key = entry.getKey().toString();
				if (key.indexOf(end_seat) == -1) {
					// System.out.println("roll_map:" + key);//用于测试
					// 调用函数,尝试更新路径
					addNum(key);
				}
			}
		}
		// 判断在经过一轮循环后use_map是否变化,如果没变化就停止,防止死循环
		for (Map.Entry<String, Integer> entry : use_map.entrySet()) {
			String key = entry.getKey().toString();
			// 判断有无变化
			if (temp_map.get(key) != use_map.get(key))
				sure_end++;
		}
		// 当有一个key值改变时
		if (sure_end == 0)
			// 结束递归
			return;
		else
			// 继续递归
			roll_map();
	}

	// 获取最小路径的key
	public String min_key() {
		int num = 0;
		String result_key = "";
		for (Map.Entry<String, Integer> entry : use_map.entrySet()) {
			String key = entry.getKey().toString();
			// 当路径长度为0,或者路径比最短路径小时,替换
			if (("".equals(result_key) && num == 0) || use_map.get(key) < num) {
				result_key = key;
				num = use_map.get(key);
			}
		}
		return result_key;
	}

	// 判断能否添加该key
	public boolean sure_add(String key) {
		String kk[] = key.split("-");
		if (kk.length >= 2) {
			String temp = "";
			for (int i = 0; i < kk.length - 2; i++) {
				temp += kk[i] + "-";
			}
			temp += kk[kk.length - 1] + "-" + kk[kk.length - 2];
			return !use_map.containsKey(temp);
		} else {
			return !use_map.containsKey(key);
		}
	}

	// 循环加入 key形式"A-B",其中A和B都是节点
	public void add_map(String key, Integer value) {
		// 加入数据map
		data_map.put(key, value);
		//
		all_list.add(key.split("-")[0]);
		all_list.add(key.split("-")[1]);
	}

	// 主函数
	public static void main(String[] args) {
		// key形式"A-B",其中A和B都是节点,value 是长度形式添加到data_map中
		// 设置开始节点start_seat,和结束节点end_seat,设置是否是有权无权(默认false,无权图)direction
		// 运行roll_map()函数即可
		DjstSF df = new DjstSF();
		data_map.put("1-2", 2);
		data_map.put("1-3", 12);
		data_map.put("1-5", 3);
		data_map.put("2-4", 6);
		data_map.put("2-3", 3);
		data_map.put("4-3", 4);
		data_map.put("3-5", 5);
		data_map.put("5-4", 2);
		data_map.put("5-6", 4);
		data_map.put("4-6", 15);
		start_seat = "1";
		end_seat = "6";
		direction = true;
		df.roll_map();
		System.out.println("最小的是" + df.min_key());
	}

}

备注:我当时测试时用的是有权图测试的,无权图也许会存在一些瑕疵。。。,抽空我再测试下无权图,图有空再配吧。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章