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