Java实现无向图邻接表

这个实现只考虑实现无向图邻接表的功能,底层使用HashMap

提供了如下的API

1. addEdge,添加一条边

2. removeEdge,删除某条边

3. containsEdge,是否包含某条边

4. show,打印展示整个图

5. edgeNum,返回边的数目

6. getAllPoints,获取所有点的集合

7. getAnotherSidePoints,获取边另一端的点

8. containsPoint,是否包含某个点

9. addPoint,添加一个点

扫描二维码关注公众号,回复: 2455407 查看本文章

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