要写一个Java版的邻接表,发现连概念都忘了。重新理解了下邻接表写了代码作为备忘:
邻接表概念(摘自:http://blog.csdn.net/jnu_simba/article/details/8866844)
对于图来说,邻接矩阵是不错的一种图存储结构,但是我们也发现,对于边数相对顶点较少的图,这种结构是存在对存储空间的极大浪费的。因此我们考虑另外一种存储结构方式:邻接表(Adjacency List),即数组与链表相结合的存储方法。
邻接表的处理方法是这样的。
1、图中顶点用一个一维数组存储,另外,对于顶点数组中,每个数据元素还需要存储指向第一个邻接点的指针,以便于查找该顶点的边信息。
2、图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以用单链表存储,无向图称为顶点vi的边表,有向图称为顶点vi作为弧尾的出边表。
Dijkstra算法
1.定义概览
Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。
问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径。(单源最短路径)
2.算法描述
1)算法思想:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。
2)算法步骤:
a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为∞。
b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。
c.以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。
d.重复步骤b和c直到所有顶点都包含在S中。
执行动画过程如下图
代码
package cn.Adjacency;
import java.util.*;
public class Vertex implements Comparable<Vertex>{
public final String name;
public ArrayList<Edge> neighbours;
public LinkedList<Vertex> path;
public double minDistance = Double.POSITIVE_INFINITY;
public Vertex previous;
public int compareTo(Vertex other){
return Double.compare(minDistance,other.minDistance);
}
public Vertex(String name){
this.name = name;
neighbours = new ArrayList<Edge>();
path = new LinkedList<Vertex>();
}
public String toString(){
return name;
}
public double getMinDistance() {
return minDistance;
}
public void setMinDistance(double minDistance) {
this.minDistance = minDistance;
}
}
package cn.Adjacency;
//To represent the edges in the graph.
public class Edge{
public final Vertex target;
public final double weight;
public Edge(Vertex target, double weight){
this.target = target;
this.weight = weight;
}
}
package cn.Adjacency;
import java.util.LinkedHashMap;
import java.util.Map;
public class Graph {
private Map<String, Vertex> vertices;
public Graph(String[] vertexNames){
vertices = new LinkedHashMap<String, Vertex>();
for(String name : vertexNames){
vertices.put(name, new Vertex(name));
}
}
public void addEdge(String srcName, String destName, int weight){
Vertex s = vertices.get(srcName);
Edge new_edge = new Edge(vertices.get(destName),weight);
s.neighbours.add(new_edge);
}
/**
* <p>
* 删除边, 取得两个顶点即可:
* 查找原顶点对应的邻接表的边,边的另一端等于目标顶点就是要删除的边
* <p>
*
* @param src 原顶点
* @param dest 目标顶点
* @return
*/
public Edge delEdge(String src, String dest){
Vertex s = vertices.get(src);
Vertex d = vertices.get(dest);
Edge delEdge = null;
for(Edge edge : s.neighbours){
if(edge.target == d){
delEdge = edge;
}
}
s.neighbours.remove(delEdge);
return delEdge;
}
/**
* <p>
* 默认最短路径充值,图被算一次选择一个顶点算了一次最短路径后会
* 更改最短路径值,要算其他顶点开始的最短路径得重新设置每个顶点最短
* 路径的初始值
* <p>
*/
public void resetMinDistance(){
for (String key : vertices.keySet()) {
Vertex v = vertices.get(key);
v.setMinDistance(Double.POSITIVE_INFINITY);
}
}
public Map<String,Vertex> getVertices() {
return vertices;
}
public Vertex getVertex(String vertName){
return vertices.get(vertName);
}
}
package cn.Adjacency;
import java.util.LinkedList;
import java.util.PriorityQueue;
/**
* <p>
* 最短路径算法
* <p>
* @author 天行健
*
*/
public class Dijkstra{
public static void main(String[] arg){
Dijkstra obj = new Dijkstra();
// Create a new graph.
Graph g = new Graph(new String[]{"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"});
// Add the required edges.
g.addEdge("v0", "v1", 4); g.addEdge("v0", "v7", 8);
g.addEdge("v1", "v2", 8); g.addEdge("v1", "v7", 11); g.addEdge("v2", "v1", 8);
g.addEdge("v2", "v8", 2); g.addEdge("v2", "v5", 4); g.addEdge("v2", "v3", 7);
g.addEdge("v3", "v2", 7); g.addEdge("v3", "v5", 14); g.addEdge("v3", "v4", 9);
g.addEdge("v4", "v3", 9); g.addEdge("v4", "v5", 10);
g.addEdge("v5", "v4", 10); g.addEdge("v5", "v3", 9); g.addEdge("v5", "v2", 4); g.addEdge("v5", "v6", 2);
g.addEdge("v6", "v7", 1); g.addEdge("v6", "v8", 6); g.addEdge("v6", "v5", 2);
g.addEdge("v7", "v0", 8); g.addEdge("v7", "v8", 7); g.addEdge("v7", "v1", 11); g.addEdge("v7", "v6", 1);
g.addEdge("v8", "v2", 2); g.addEdge("v8", "v7", 7); g.addEdge("v8", "v6", 6);
// Calculate Dijkstra.
obj.calculate(g.getVertex("v0"));
// Print the minimum Distance.
for(Vertex v : g.getVertices().values()){
System.out.print("Vertex - "+v+" , Dist - "+ v.minDistance+" , Path - ");
for(Vertex pathvert:v.path) {
System.out.print(pathvert+" ");
}
System.out.println(""+v);
}
System.out.println("---------**********------------");
Edge delEdge = g.delEdge("v0", "v7");
System.out.println("被删除的边(已字符为顶点主键):" + delEdge);
g.resetMinDistance();
obj.calculate(g.getVertex("v0"));
// 删除一条边后的最短路径
for(Vertex v : g.getVertices().values()){
System.out.print("Vertex - " + v + " , Dist - " + v.minDistance
+ " , Path - ");
for (Vertex pathvert : v.path) {
System.out.print(pathvert + " ");
}
System.out.println("" + v);
}
}
public void calculate(Vertex source){
// Algo:
// 1. Take the unvisited node with minimum weight.
// 2. Visit all its neighbours.
// 3. Update the distances for all the neighbours (In the Priority Queue).
// Repeat the process till all the connected nodes are visited.
source.minDistance = 0;
PriorityQueue<Vertex> queue = new PriorityQueue<Vertex>();
queue.add(source);
while(!queue.isEmpty()){
Vertex u = queue.poll();
for(Edge neighbour:u.neighbours){
Double newDist = u.minDistance+neighbour.weight;
if(neighbour.target.minDistance>newDist){
// Remove the node from the queue to update the distance value.
queue.remove(neighbour.target);
neighbour.target.minDistance = newDist;
// Take the path visited till now and add the new node.s
neighbour.target.path = new LinkedList<Vertex>(u.path);
neighbour.target.path.add(u);
//Reenter the node with new distance.
queue.add(neighbour.target);
}
}
}
}
}