package art.programming.algorithm; public class HammingDistance { public static int getHammingDistance(String a, String b){ if (a.length() != b.length()) throw new IllegalArgumentException("The length of different string must be the same"); int len = a.length(); int sum = 0; for (int i=0; i< len; i++){ if (a.charAt(i) != b.charAt(i)) sum += 1; } return sum; } }
顶点 |
列表下标 |
关联顶点下标 |
hit |
0 |
1 |
hot |
1 |
2,4 |
dot |
2 |
1,3,4 |
dog |
3 |
2,5,6 |
lot |
4 |
1,2,5 |
log |
5 |
3,4,6 |
cog |
6 |
3,5 |
package art.programming.algorithm; import java.util.ArrayList; import java.util.List; import java.util.PriorityQueue; import java.util.Queue; public class Graph { private Vertex[] vertexes; private Edge[] edges; public Graph(String[] vertexNames){ vertexes = new Vertex[vertexNames.length]; //初始化每个节点 for (int i=0; i< vertexNames.length; i++){ vertexes[i] = new Vertex(vertexNames[i], i, Integer.MAX_VALUE); } //初始化每条边 edges = new Edge[vertexNames.length]; int len = this.vertexes.length; for (int i=0; i < len; i++){ edges[i] = new Edge(); for(int j=0; j < len; j++){ boolean isHammingDistanceAs1 = HammingDistance.getHammingDistance(this.vertexes[i].getName(), this.vertexes[j].getName()) == 1; //如果i和j之间的汉明距离是1,那么说明他们之间有连接 if (isHammingDistanceAs1){ edges[i].addNeighbor(j); } } } } private static class Vertex { private int weight; private int index; //这个顶点在顶点集合中的下标 private String name; public Vertex(String name, int index, int weight){ this.index = index; this.weight = weight; this.name = name; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } public int getIndex() { return index; } public String getName() { return name; } public void setName(String name) { this.name = name; } } private static class Edge{ private List<Integer> neighbors = new ArrayList<Integer>(); public void addNeighbor(int i){ neighbors.add(i); } public List<Integer> getNeighbors(){ return neighbors; } } }
package art.programming.algorithm; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.PriorityQueue; import java.util.Queue; import java.util.Set; import java.util.Stack; public class Graph { private Vertex[] vertexes; private Edge[] edges; public Graph(String[] vertexNames){ vertexes = new Vertex[vertexNames.length]; //初始化顶点 for (int i=0; i< vertexNames.length; i++){ vertexes[i] = new Vertex(vertexNames[i], i, Integer.MAX_VALUE); } //初始化边 edges = new Edge[vertexNames.length]; int len = this.vertexes.length; for (int i=0; i < len; i++){ edges[i] = new Edge(); for(int j=0; j < len; j++){ boolean isHammingDistanceAs1 = HammingDistance.getHammingDistance(this.vertexes[i].getName(), this.vertexes[j].getName()) == 1; //如果两个字符的汉明距离为1,说明它们相连接 if (isHammingDistanceAs1){ edges[i].addNeighbor(j); } } } } //打印 public void printShortestPath(String source, String destination){ Vertex[] sDist = getDistances(source, destination); Vertex distVertex = null; for (Vertex v : vertexes){ if (v.getName().equals(destination)) distVertex = v; } int minWeight=Integer.MAX_VALUE; Set<Vertex> minPathSet = new HashSet<Vertex>(); for (int i : edges[distVertex.getIndex()].getNeighbors()){ if ( sDist[i].getWeight() <= minWeight){ minPathSet.add(sDist[i]); minWeight = sDist[i].getWeight(); }else{ minPathSet.remove(sDist[i]); } } for (Vertex v : minPathSet){ Stack<Vertex> stack = new Stack<Vertex>(); stack.add(distVertex); Vertex temp = v; while(temp.predecessor!=null){ stack.add(temp); temp = temp.getPredecessor(); } for (Vertex v1 : stack){ System.out.print(v1.name + "->"); } System.out.print(source+"\n"); } } //求源顶点到每个顶点的最小权值 public Vertex[] getDistances(String source, String destination){ Queue<Vertex> unvisitedQueue = new PriorityQueue<Vertex>(); initialize(source, unvisitedQueue); //放源顶点到各个顶点的最小权值 Vertex[] sDist = new Vertex[vertexes.length]; while(!unvisitedQueue.isEmpty()){ //取出最小的 Vertex u = unvisitedQueue.poll(); //遍历它的邻居 List<Integer> neighbors = edges[u.index].getNeighbors(); for (int i : neighbors){ if (sDist[i] != null) continue; //¸Ã¶¥µãµ½Ô´µãµÄ×îС¾àÀëÒѾ¼ÆËã¹ýÁË¡£ relax(u, vertexes[i]); } sDist[u.index] = u; decreaseKey(unvisitedQueue); } return sDist; } private void decreaseKey(Queue<Vertex> unvisitedQueue){ Vertex temp = unvisitedQueue.poll(); if (temp!=null) unvisitedQueue.add(temp); } /** * 初始化 * @param sourceVertexIndex * @param unvisitedVertexes * @param visitedQueue */ private void initialize(String sourceVertexName, Queue<Vertex> visitedQueue){ for (int i=0; i<vertexes.length; i++){ //如果是源顶点,它的权值为0,否则为无穷大 if (vertexes[i].getName().equals(sourceVertexName)){ vertexes[i].setWeight(0); } visitedQueue.add(vertexes[i]); } } private void relax(Vertex u, Vertex v){ //如果新路径算出来的权值比原先的小,替换原先的 if (v.weight >= u.weight + 1){ v.weight = u.weight + 1; v.predecessor = u; } } private static class Vertex implements Comparable<Vertex>{ private int weight; private int index; private Vertex predecessor; private String name; public Vertex(String name, int index, int weight){ this.index = index; this.weight = weight; this.name = name; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } public Vertex getPredecessor() { return predecessor; } public void setPredecessor(Vertex predecessor) { this.predecessor = predecessor; } public int getIndex() { return index; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int compareTo(Vertex o) { if (weight > o.weight) return 1; if (weight < o.weight) return -1; return 0; } public int hashCode(){ return index; } public String toString(){ return "Name: "+this.name +" Weight:"+weight + " Predessesor:"+ (this.predecessor == null ? "null" : this.predecessor.getName()); } } private static class Edge{ private List<Integer> neighbors = new ArrayList<Integer>(); public void addNeighbor(int i){ neighbors.add(i); } public List<Integer> getNeighbors(){ return neighbors; } } }
package art.programming.algorithm; import org.junit.Test; public class GraphTest { @Test public void findShortestPath(){ String[] nodes = {"hit","hot","dot","dog","lot","log","cog"}; Graph graph = new Graph(nodes); graph.printShortestPath("hit", "cog"); } }