Java实现无向图邻接表

这个实现只考虑实现无向图邻接表的功能,底层使用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();	
	}

}


猜你喜欢

转载自blog.csdn.net/esir82/article/details/78692888