最近看了點有向圖的內容,參考開源項目做了一個簡單版本,直接貼代碼。
/** * 有向圖接口,定義需要實現的各個方法,可以選擇使用鄰接矩陣或者鄰接鏈表來實現 * @param <V> V代表端點,可以根據需要設置器數據類型 */ public interface DGraph<V> { /**深度優先遍歷*/ public static final int ITERATOR_TYPE_DFS = 0; /**廣度優先遍歷*/ public static final int ITERATOR_TYPE_BFS = 0; /** * 添加一個端點 * @param v * @return 新增端點的編號,-1表示插入失敗 */ public int add(V v); /** * 添加一個邊 * @param e */ public void add(Edge<V> e); /** * 刪除一個頂點,與其相連的邊也會被刪除 * @param v * @return 被刪除的頂點,如果找不到對應頂點則返回null */ public V remove(V v); /** * 刪除一條邊 * @param e * @return 被刪除的邊,如果找不到對應的邊則返回null */ public Edge<V> remove(Edge<V> e); /** * 獲得一個頂點 * @param index 頂點的編號 * @return */ public V get(int index); /** * 獲得一條邊 * @param src 起點的編號 * @param dest 終點的編號 * @return */ public Edge<V> get(int src, int dest); /** * 得到當前圖的迭代器,用於對圖進行遍歷 * @param type 遍歷類型,深度優先或者廣度優先 * @param root 從哪個點開始遍歷 * @return */ public Iterator<V> iterator(int type, V root); /** * 將圖轉換為無環圖 */ public void convertDAG(); }
/** * 一條邊,可以根據需要繼承此類 * @param <V> */ public class Edge<V> { /**起點*/ private V src; /**終點*/ private V dest; /**權值*/ private double weight; /** * 不帶權值的一條邊 * @param src * @param dest */ public Edge(V src, V dest) { this(src, dest, 0); } /** * 帶權值的一條邊 * @param src * @param dest * @param weight */ public Edge(V src, V dest, double weight) { this.src = src; this.dest = dest; this.weight = weight; } /** * 獲取起點 * @return */ public V getSource() { return this.src; } /** * 獲取終點 * @return */ public V getDest() { return this.dest; } /** * 獲取權值 * @return */ public double getWeight() { return this.weight; } @Override public String toString() { String ret = String.format("src : %s , dest : %s , weight : %s", src, dest, weight); return ret; } }
/** * 鄰接鏈表(Adjacency List)實現的有向圖 * @param <V> */ public class ListDGraph<V> implements DGraph<V>{ /** * 頂點對象,其中有對應的頂點以及從以此頂點為起點的邊 */ private class VE { /**此頂點*/ private V v; /**以此頂點為起點的邊的集合,是一個列表,列表的每一項是一條邊*/ private List<Edge<V>> mEdgeList; /** * 構造一個新的頂點對象 * @param v */ public VE(V v) { this.v = v; this.mEdgeList = new LinkedList<Edge<V>>(); Utils.log("VE construct : %s", v); } @Override public String toString() { String ret = String.format("v : %s , list len : %s", v, mEdgeList.size()); return ret; } /** * 將一條邊添加到邊集合中 * @param e */ public void addEdge(Edge<V> e) { Utils.log("add edge : %s", e); if(getEdge(e.getDest()) == null) { mEdgeList.add(e); } else { Utils.log("edge exist : %s", e); } } /** * 讀取某條邊 * @param dest * @return */ public Edge<V> getEdge(V dest) { Edge<V> ret = null; if(dest != null) { for(Edge<V> edge : mEdgeList) { if(edge.getDest() != null && dest.equals(edge.getDest())) { Utils.log("get edge : %s", edge); ret = edge; break; } } } return ret; } /** * 讀取某條邊 * @param dest * @return */ public Edge<V> removeEdge(V dest) { Edge<V> ret = null; if(dest != null) { for(Edge<V> edge : mEdgeList) { if(edge.getDest() != null && dest.equals(edge.getDest())) { Utils.log("remove edge : %s", edge); ret = edge; mEdgeList.remove(edge); break; } } } return ret; } } /** * 廣度優先的迭代器 */ private class BFSIterator implements Iterator<V> { /**已訪問過的頂點列表*/ private List<V> mVisitList = null; /**待訪問的頂點隊列*/ private Queue<V> mVQueue = null; /** * 構造廣度優先迭代器 * @param dg * @param root */ public BFSIterator(V root) { mVisitList = new LinkedList<V>(); mVQueue = new LinkedList<V>(); //將初始節點入隊列 mVQueue.offer(root); } @Override public boolean hasNext() { Utils.log("queue size : " + mVQueue.size()); if(mVQueue.size() > 0) { return true; } else { return false; } } @Override public V next() { //1.取隊列元素 V v = mVQueue.poll(); if(v != null) { //2.將此元素的鄰接邊中對應頂點入隊列,這些頂點需要符合以下條件: //1)沒訪問過; //2)不在隊列中; VE ve = getVE(v); if(ve != null) { List<Edge<V>> list = ve.mEdgeList; for(Edge<V> edge : list) { V dest = edge.getDest(); if(!VinList(dest, mVisitList.iterator()) && !VinList(dest, mVQueue.iterator())) { mVQueue.offer(dest); Utils.log("add to queue : " + dest); } } } //3.將此頂點添加到已訪問過的頂點列表中 mVisitList.add(v); } //4.返回出隊列的元素 return v; } @Override public void remove() { // 暫時不實現 } } /**頂點列表,由於會經常進行插入刪除,使用鏈表隊列*/ private LinkedList<VE> mVEList; /** * 構造鄰接鏈表有向圖 */ public ListDGraph() { mVEList = new LinkedList<VE>(); Utils.log("ListDGraph construct!"); } @Override public int add(V v) { int index = -1; if(v != null) { Utils.log("add v: %s", v); VE list = new VE(v); mVEList.add(list); index = mVEList.indexOf(list); } return index; } @Override public void add(Edge<V> e) { if(e != null) { Utils.log("add edge: %s", e); VE ve = getVE(e.getSource()); if(ve != null) { //若邊的起點已經在列表里,則直接將其添加到對應的頂點對象中 ve.addEdge(e); } else { //否則提示錯誤 Utils.log("Error, can't find v : %s", e.getSource()); } } } @Override public V remove(V v) { V ret = null; VE ve = removeVE(v); if(ve != null) { ret = ve.v; } removeRelateEdge(v); return ret; } @Override public Edge<V> remove(Edge<V> e) { Edge<V> ret = null; if(e != null) { VE ve = getVE(e.getSource()); if(ve != null) { ret = ve.removeEdge(e.getDest()); } } return ret; } @Override public V get(int index) { V ret = null; if(index >=0 && index < mVEList.size()) { VE ve = mVEList.get(index); if(ve != null) { ret = ve.v; Utils.log("get , index : %s , v : %s", index, ret); } } return ret; } @Override public Edge<V> get(int src, int dest) { Edge<V> ret = null; V s = get(src); V d = get(dest); if(s != null && d != null) { VE ve = getVE(s); if(ve != null) { ret = ve.getEdge(d); } } return ret; } @Override public Iterator<V> iterator(int type, V root) { Iterator<V> ret = null; if(type == ITERATOR_TYPE_BFS) { //廣度優先的迭代器 ret = new BFSIterator(root); } else if(type == ITERATOR_TYPE_DFS){ //深度優先的迭代器,暫時未實現 } else { //... } return ret; } @Override public void convertDAG() { // TODO Auto-generated method stub } //////////////////////////////私有方法////////////////////////////// /** * 從頂點對象列表中讀取輸入頂點對應的對象 * @param v * @return */ private VE getVE(V v) { VE ret = null; if(v != null) { for(VE ve : mVEList) { if(ve.v != null && v.equals(ve.v)) { Utils.log("getVE : %s", ve); ret = ve; break; } } } return ret; } /** * 從頂點對象列表中刪除輸入頂點對應的對象 * @param v * @return 刪除的頂點對象 */ private VE removeVE(V v) { VE ret = null; if(v != null) { for(VE ve : mVEList) { if(ve.v != null && v.equals(ve.v)) { Utils.log("removeVE : %s", v); ret = ve; mVEList.remove(ve); break; } } } return ret; } /** * 刪除以某個點作為重點的邊 * @param v */ private void removeRelateEdge(V v) { if(v != null) { for(VE ve : mVEList) { ve.removeEdge(v); } } } /** * 判斷某個端點是否在某個列表里 * @param v * @param it * @return */ private boolean VinList(V v, Iterator<V> it) { boolean ret = false; if(v != null && it != null) { while(it.hasNext()) { V v_temp = it.next(); if(v_temp != null && v_temp.equals(v)) { ret = true; break; } } } return ret; } }
/** * 一些工具類 */ public class Utils { /** * 打印信息 * @param t */ public static void log(Object t) { System.out.println(t); } /** * 打印信息 * @param t */ public static void log(String format, Object... args) { String str = String.format(format, args); System.out.println(str); } }
使用方法示例:
public class ListDGraphTest { DGraph<String> mDG = new ListDGraph<String>(); @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void testAll() { Utils.log("===============add v================="); mDG.add("1"); mDG.add("2"); mDG.add("3"); mDG.add("4"); mDG.add("5"); mDG.add("6"); mDG.add("7"); mDG.add("8"); Utils.log("===============add edge================="); mDG.add(new Edge<String>("1", "2")); mDG.add(new Edge<String>("1", "3")); mDG.add(new Edge<String>("2", "4")); mDG.add(new Edge<String>("2", "5")); mDG.add(new Edge<String>("3", "6")); mDG.add(new Edge<String>("3", "7")); mDG.add(new Edge<String>("4", "8")); mDG.add(new Edge<String>("8", "5")); mDG.add(new Edge<String>("6", "7")); Utils.log("===============test travelling================="); Iterator<String> it = mDG.iterator(DGraph.ITERATOR_TYPE_BFS, "1"); while(it.hasNext()) { String s = it.next(); Utils.log("next : %s", s); } Utils.log("===============test travelling2================="); it = mDG.iterator(DGraph.ITERATOR_TYPE_BFS, "2"); while(it.hasNext()) { String s = it.next(); Utils.log("next : %s", s); } Utils.log("===============test others================="); mDG.get(0); mDG.get(0, 1); mDG.remove("6"); mDG.remove(new Edge<String>("3", "7")); } }