一個簡單的有向圖Java實現


最近看了點有向圖的內容,參考開源項目做了一個簡單版本,直接貼代碼。

 

/**
 * 有向圖接口,定義需要實現的各個方法,可以選擇使用鄰接矩陣或者鄰接鏈表來實現
 * @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"));
    }
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM