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());
	}

}

備註:我當時測試時用的是有權圖測試的,無權圖也許會存在一些瑕疵。。。,抽空我再測試下無權圖,圖有空再配吧。。。

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