图的定义:图G={V,E}由定点V和边E组成。边就是顶点对,如果点对是有序的,那么图就是有向图;否则就是无向图。有的时候边上还有权值的项。图有两种存储方式,一种是邻接矩阵,一种是邻接表。如果用邻接矩阵进行存储的话,当顶点很多但是变又很少的情况下,此时的矩阵是稀疏矩阵,会造成空间的浪费。邻接表就是顶点数组,与这个顶点有关联的顶点会用一个List进行存储。这样会节省不必要的空间的浪费。
定义后继节点的类
public class info {
//需要指向这个节点在数组中的位置
public int index;
//这两个顶点之间的权值
public int weight;
}
定义顶点的数组
import java.util.ArrayList;
public class minDistNode {
//需要节点的编号
public String number;
//需要有个标识这个节点有没有被访问
public boolean visited;
//需要个从开始到这点的距离
public int dis;
//这个节点上一个节点的位置(求最短路径)
public minDistNode path;
//这个节点的后继节点
public ArrayList<info> adj;
//这个节点的入度(拓扑排序)
public int indegree;
public minDistNode() {
this.indegree = 0;
}
}
拓扑排序
在现实生活中,事情是有先后的;比如大学课程的安排,一些课只能在完成先修课之后才能学习,这样就得为这些课安排一个先后顺序,就可以用拓扑排序来完成。节点的v入度就是就是<u,v>的条数,一定是存在一个节点的入度为0的入度的,这样的就可以先行处理,然后把这个节点的直接后继节点的入度-1。然后在输出节点中入度为0的节点。
最短路径算法
单源最短路径很像搜索图的方法的广度优先遍历。该方法按层处理顶点;距离开始点最近的那些顶点首先被求值,而最远的那些顶点最后被求值。这很像树的层序遍历。
dijkstra
Dijkstra算法按阶段进行,正像无最短路径的算法一样。在每个阶段,Dijkstra算法选择一个顶点v,它在所有的unvisited顶点中有最小的dis,同时算法还得声明s->v的最短路径是已知的。剩余的阶段有dis值的更新工作完成。
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.TreeSet;
public class minDistance {
//声明邻接表数组
minDistNode[] vertex;
//声明节点数组
String[] vertexNum;
//创建邻接表
public void creatMap() throws IOException {
//文件路径
String path = "G:\\eclipse\\DataStructure\\src\\minDistGraph.txt";
FileReader reader = new FileReader(path);
BufferedReader br = new BufferedReader(reader);
String line = null;
//要获取共有多少个节点,选择用set集合
Set<String> set = new TreeSet<>();
//需要把行数据进行数组化
String[] arr;
//因为这些数据建立邻接表的时候还要用,所以先存取起来
StringBuilder res = new StringBuilder();
while((line = br.readLine())!=null) {
res.append(line+"\n");
arr = line.split(" ");
set.add(arr[0]);
set.add(arr[1]);
}
//关闭文件链接
br.close();
reader.close();
//得到了共有多少个节点
int vCount = set.size();
//建立节点数组
vertex = new minDistNode[vCount];
//节点的后继
ArrayList<info> list;
//先获取节点,为了方便,将其存入数组中
Iterator<String> iter = set.iterator();
vertexNum = new String[vCount];
int index = 0;
while(iter.hasNext()) {
vertexNum[index++] = iter.next();
}
for(int i = 0;i<vCount;i++) {
vertex[i] = new minDistNode();
}
//初始化数组
for(int i = 0;i<vCount;i++) {
list = new ArrayList<>();
index = getIndex(vertexNum[i]);
vertex[index].number = vertexNum[i];
vertex[index].adj = list;
vertex[index].dis = Integer.MAX_VALUE;
vertex[index].visited = false;
vertex[index].path = null;
}
//获取边的数据
String[] edge = res.toString().split("\n");
//两点之间边的信息
info infor;
//建立邻接表
for(int i = 0;i<edge.length;i++) {
arr = edge[i].split(" ");
//首先找到这个开始节点的数组位置
index = getIndex(arr[0]);
//为这个后继节点补充信息
infor = new info();
infor.index = getIndex(arr[1]);
vertex[infor.index].indegree++;
infor.weight = Integer.parseInt(arr[2].trim());
vertex[index].adj.add(infor);
}
}
//获取节点在数组的位置
public int getIndex(String s ) {
for(int i = 0;i<vertexNum.length;i++) {
if(vertexNum[i].equals(s)) {
return i;
}
}
throw new IllegalArgumentException();
}
//进行拓扑排序
public void sort() {
for(int count = 0;count<vertexNum.length;count++) {
minDistNode node = getIndegreeIsZero();
if(node == null) {
throw new IllegalArgumentException();
}
System.out.println(node.number);
node.visited = true;
ArrayList<info> info = node.adj;
for(info t :info) {
vertex[t.index].indegree--;
}
}
}
private minDistNode getIndegreeIsZero() {
for(int i = 0;i<vertexNum.length;i++) {
int index = getIndex(vertexNum[i]);
if(vertex[index].indegree == 0 && !vertex[index].visited) {
return vertex[index];
}
}
return null;
}
//得到最短路径,如果权值是1
public void disLength(String start) {
//获得这个节点的数组位置
int index = getIndex(start);
//领这个位置的距离为0
vertex[index].dis = 0;
//遍历整个节点
for(int count = 0;count<vertexNum.length;count++) {
//遍历所有节点
for(minDistNode node : vertex) {
if(node.visited == false && node.dis == count) {
node.visited = true;
ArrayList<info> infor = node.adj;
for(info t:infor) {
if(vertex[t.index].dis == Integer.MAX_VALUE) {
vertex[t.index].dis = count+1;
vertex[t.index].path = node;
}
}
}
}
}
}
//权值不是1的时候的最短路径
public void minLength(String start) {
int index = getIndex(start);
vertex[index].dis = 0;
Queue<minDistNode> queue = new LinkedList<>();
queue.add(vertex[index]);
while(!queue.isEmpty()) {
minDistNode node = queue.poll();
node.visited = true;
ArrayList<info> infor = node.adj;
for(info t:infor) {
if(vertex[t.index].dis == Integer.MAX_VALUE) {
vertex[t.index].dis = node.dis+t.weight;
vertex[t.index].path = node;
}
else {
if(vertex[t.index].dis > node.dis+t.weight) {
vertex[t.index].dis = node.dis+t.weight;
vertex[t.index].path = node;
}
}
if(vertex[t.index].visited == false) {
queue.add(vertex[t.index]);
}
}
}
}
//最短路径输出
public void print(String end) {
int index = getIndex(end);
if(vertex[index].path!=null) {
print(vertex[index].path.number);
}
System.out.println(vertex[index].number);
}
}
像这样的文件格式: