Java實現無向圖鄰接表
阿新 • • 發佈:2019-01-04
這個實現只考慮實現無向圖鄰接表的功能,底層使用HashMap。
提供瞭如下的API:
1. addEdge,新增一條邊
2. removeEdge,刪除某條邊
3. containsEdge,是否包含某條邊
4. show,列印展示整個圖
5. edgeNum,返回邊的數目
6. getAllPoints,獲取所有點的集合
7. getAnotherSidePoints,獲取邊另一端的點
8. containsPoint,是否包含某個點
9. addPoint,新增一個點
10. removePoint,刪除某個點
11. pointNum,返回圖內點的總數
12. breadhFirstSearch,廣度優先遍歷
13. depthFirstSearch,深度優先遍歷
14. isConnected,圖是否是連通的
15. toString,重寫
16. minSpanningTree,返回圖的最小生成樹
異常處理:
1. ElementNotFoundException
2. EmptyCollectionException
3. NonComparableElementException
實體類:
1. Side
輔助類:
1. ArrayHeap(陣列實現的二叉最小堆)
package graph; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Queue; import java.util.Set; /** * * @author Administrator * 無向圖鄰接表 * @param <K> 頂點的Label * @param <V> 邊的權重 */ public class NearTable<K,V> { Map<K,Map<K,V>> table = new HashMap<K,Map<K,V>>(); int edgeNum = 0; //是否是空圖 public boolean isEmpty(){ return table.isEmpty(); } /* * 針對無向圖 */ public boolean containsEdge(K p1,K p2){ if(!table.containsKey(p1)){ return false; } if(!table.containsKey(p2)){ return false; } if(!table.get(p1).containsKey(p2)){ return false; } if(!table.get(p2).containsKey(p1)){ return false; } return true; } public boolean containsEdge(K p1,K p2,V weight){ if(this.containsEdge(p1, p2)){ V weight1 = table.get(p1).get(p2); V weight2 = table.get(p2).get(p1); if(weight1 == weight && weight2 == weight){ return true; } if(weight1.equals(weight) && weight2.equals(weight)){ return true; } } return false; } public boolean addEdge(K p1,K p2,V weight){ if(this.containsEdge(p1, p2)){ return false; } if(!table.containsKey(p1)){ table.put(p1, new HashMap<K,V>()); } if(!table.containsKey(p2)){ table.put(p2, new HashMap<K,V>()); } table.get(p1).put(p2, weight); table.get(p2).put(p1, weight); this.edgeNum++; return true; } public boolean removeEdge(K p1,K p2) throws EmptyCollectionException, ElementNotFoundException{ if(this.isEmpty()){ return false; } if(!this.containsEdge(p1, p2)){ return false; } table.get(p1).remove(p2); table.get(p2).remove(p1); this.edgeNum--; return true; } public void show(){ Set<Entry<K, Map<K, V>>> set = table.entrySet(); for(Entry<K, Map<K, V>> e : set){ Set<Entry<K, V>> temp = e.getValue().entrySet(); if(temp.size() > 0){ System.out.print(e.getKey() + " -> "); for(Entry<K, V> e1 : temp){ System.out.print(e1.getKey() + "(" + e1.getValue() + ") "); } System.out.println(); } } } public int edgeNum(){ return edgeNum; } public Set<K> getAllPoints(){ return table.keySet(); } public Set<K> getAnotherSidePoints(K point){ //要做非空判斷 //continue... if(!table.containsKey(point)){ try { throw new ElementNotFoundException(this.getClass().getName() + ", Point:" + point.toString()); } catch (ElementNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return table.get(point).keySet(); } public boolean containsPoint(K point){ return table.containsKey(point); } public boolean addPoint(K point){ if(this.containsPoint(point)){ return false; } table.put(point, new HashMap<K,V>()); return true; } @SuppressWarnings("unchecked") public boolean removePoint(K point){ if(!this.containsPoint(point)){ return false; } Set<K> pointsSet = this.getAnotherSidePoints(point); Object [] pointsArray = pointsSet.toArray(); for(int i=pointsArray.length-1;i>=0;i--){ try { this.removeEdge(point, (K)pointsArray[i]); } catch (EmptyCollectionException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ElementNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } table.remove(point); return true; } public int pointNum(){ return table.size(); } public List<K> breadhFirstSearch(K startPoint){ if(!this.containsPoint(startPoint)){ try { throw new ElementNotFoundException(this.getClass().getName() + ", Point:" + startPoint.toString()); } catch (ElementNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } List<K> resultList = new ArrayList<K>(this.pointNum()); Queue<K> queue = new ArrayDeque<K>(); queue.add(startPoint); while(!queue.isEmpty()){ K current = queue.remove(); if(!resultList.contains(current)){ resultList.add(current); queue.addAll(this.getAnotherSidePoints(current)); } } return resultList; } public List<K> depthFirstSearch(K parent,List<K> result){ if(result == null){ result = new ArrayList<K>(); } result.add(parent); for(K key : this.getAnotherSidePoints(parent)){ if(!result.contains(key)){ this.depthFirstSearch(key, result); } } return result; } /* * 是否是連通的 */ public boolean isConnected(){ for(K point : this.getAllPoints()){ List<K> result = this.breadhFirstSearch(point); if(result.size() != this.pointNum()){ return false; } } return true; } @Override public String toString() { return table.toString(); } //for minimal spanning tree Map<K,V> getConnectedSides(K point){ return table.get(point); } //for minimal spanning tree void visit(List<K> hasVisited,ArrayHeap<Side<K,V>> heap,K point){ //mark as visited hasVisited.add(point); //all sides contain point Map<K,V> connectedSides = this.getConnectedSides(point); //all points on the other side Set<K> connectedPoints = connectedSides.keySet(); //add all sides to minimal heap for(K p:connectedPoints){ if(!hasVisited.contains(p)){ try { heap.addElement(new Side<K,V>(point,p,connectedSides.get(p))); } catch (NonComparableElementException e) { e.printStackTrace(); } } } } /* * Prim algorithm */ @SuppressWarnings("unchecked") public NearTable<K,V> minSpanningTree() throws EmptyCollectionException, NonComparableElementException{ //if the graph is empty,throw exception if(this.isEmpty()){ throw new EmptyCollectionException(this.getClass().getName()); } //if it is not connected, return empty graph if(!this.isConnected()){ return new NearTable<K,V>(); } //minimal heap ArrayHeap<Side<K,V>> heap = new ArrayHeap<Side<K,V>>(); //minimal spanning tree NearTable<K,V> result = new NearTable<K,V>(); //has visited points List<K> hasVisited = new ArrayList<K>(); //get all points Set<K> points = table.keySet(); //get first point as start point K point = (K) points.toArray()[0]; //visit start point this.visit(hasVisited, heap, point); //stop if get all point or heap is empty while((result.pointNum() < this.pointNum()) || !heap.isEmpty()){ //minimal side Side<K,V> side = heap.removeMin(); K pointA = side.getPointA(); K pointB = side.getPointB(); //skip invalid side if(hasVisited.contains(pointA) && hasVisited.contains(pointB)){ continue; } //add to minimal spanning tree result.addEdge(side.getPointA(), side.getPointB(), side.getWeight()); if(!hasVisited.contains(pointA)){ this.visit(hasVisited, heap, pointA); } if(!hasVisited.contains(pointB)){ this.visit(hasVisited, heap, pointB); } } return result; } public static void main(String[] args) throws EmptyCollectionException, NonComparableElementException { NearTable<String,Integer> table1 = new NearTable<String,Integer>(); table1.addEdge("1", "2", 12); table1.addEdge("1", "4", 6); table1.addEdge("2", "4", 8); table1.addEdge("2", "5", 3); table1.addEdge("3", "4", 11); table1.addEdge("3", "5", 1); table1.show(); System.out.println("--------------------------"); table1.minSpanningTree().show(); } }