迪杰斯特拉算法是典型最短路径算法,用于计算图或网中某个特定顶点到其他所有顶点的最短路径。主要特点是以起始点为中心向外,层层扩展,直到扩展覆盖所有顶点。
那么废话不多说,开始建立有向图,建立图节点,对象有三个,代码注释了
class Mapnode{
public ArrayList<Mapnode> inlist=new ArrayList<>();//入弧
public ArrayList<Mapnode> outlist=new ArrayList<>();//出弧
public String name;//写节点名字
}
手动写入节点,注意要按顺序写,因为节点的姓名和权值关系很大,不能跳着写,这里我加了判断,有兴趣的小伙伴可以适当改进,邻接矩阵大小可以设的很大,就不怕溢出了,这里我只设了6
public class Dijkstra {
public static int[][] Adjacency=new int[6][6];//邻接矩阵,我是用来计算权值的
public static HashMap<String, Integer> map=new HashMap<>();//本来是用来判断是否有重复节点,不过用不到了
public static ArrayList<Mapnode> list=new ArrayList<>();//存放所有节点
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=1;
while(true){
if(n==1){
Mapnode node=new Mapnode();
node.name="v0";
list.add(node);
n++;
}
System.out.println("请问你要继续创建图节点吗(1/0)");
int shuru=sc.nextInt();
if(shuru==0){
break;
}else if(shuru==1){
Mapnode node=new Mapnode();
System.out.println("请输入节点姓名:(v0/v1),按顺序来");
String name=sc.next();
if(((int)name.charAt(1))-48!=list.size()){
System.out.println(((int)name.charAt(1))-48!=list.size());
System.out.println(name.charAt(1));
System.out.println(list.size());
System.out.println("输入错误,请重新输节点名称");
}else {
list.add(node);
node.name=name;
System.out.println("创建成功");
}
}else{
System.out.println("请重新输入");
}
}
}
运行结果图,我用的eclipse(
之后是节点之间的相连并设置权值大小,这里我直接用的某视频的值写入了,这里可以写进方法里,博主比较懒,直接写主函数里了(
while(true){
System.out.println("还要继续相连吗");
int judge=sc.nextInt();
if(judge==1){
System.out.println("请输入要连接的节点");
String node1=sc.next();
System.out.println("请输入指向的节点");
String node2=sc.next();
System.out.println("请输入权值");
int num=sc.nextInt();
Adjacency[(int)node1.charAt(1)-48][(int)node2.charAt(1)-48]=num;
Mapnode node=list.get((int)node1.charAt(1)-48);
node.outlist.add(list.get((int)node2.charAt(1)-48));
list.get((int)node2.charAt(1)-48).inlist.add(node);
System.out.println("连接成功");
}else{
break;
}
}
运行结果图,写入的值我直接给你了,省的你在写(我这么好,不给个赞说不过去吧(doge))
//1 v1 v2 1 1 v0 v1 10 1 v0 v4 5 1 v4 v2 9 1 v4 v3 2 1 v1 v4 2 1 v4 v1 3 1 v2 v3 4 1 v3 v0 7 1 v3 v2 6 0
输出连接图像,相信大家能理解这段,可以简化一点,也留给大家了(
for(int i=0;i<list.size();i++){
System.out.println(list.get(i).name);
for(int j=0;j<list.get(i).outlist.size();j++){
System.out.print("----"+Adjacency[(int)list.get(i).name.charAt(1)-48][(int)list.get(i).outlist.get(j).name.charAt(1)-48]+"---->"+list.get(i).outlist.get(j).name);
System.out.println();
}
}
结果图,中间是权值
之后就是我们的缔结斯特拉算法了,首先输入起始节点,从起始节点开始,首先初始化dist(最短节点距离)遍历起始节点的出度,将每个出度节点的权值写入dist数组,将fina起始节点设置为true,代表此节点已经被找到了最短距离,然后写入路径前驱,路径前驱设置为当前最小路径的节点,之后循环找到fina为false的最小dist节点,从最小的dist入手,找到该节点并遍历该节点的出度,重新计算dist,也就是,该节点的dist加上该节点到出度节点的权值,比较大小,要是小于原来的dist就替换成更小的距离,并将该出度节点的前驱节点改为此节点,循环遍历即可
boolean []fina=new boolean[list.size()];//标记是否已找到最短路径
int dist[]=new int[list.size()];//最短路径长度
int path[]=new int[list.size()];//路径前驱
for(int i=0;i<dist.length;i++){
dist[i]=99999;
path[i]=-1;
}
System.out.println("请输入起始的节点:");
String start=sc.next();
fina[(int)start.charAt(1)-48]=true;
dist[(int)start.charAt(1)-48]=0;
path[(int)start.charAt(1)-48]=-1;
//初始化距离
for(Mapnode i:list.get((int)start.charAt(1)-48).outlist){
dist[(int)i.name.charAt(1)-48]=Adjacency[(int)start.charAt(1)-48][(int)i.name.charAt(1)-48];
path[(int)i.name.charAt(1)-48]=(int)start.charAt(1)-48;
System.out.println(Adjacency[(int)start.charAt(1)-48][(int)i.name.charAt(1)-48]);
}
//找到最短路径
for(int j=0;j<list.size()-1;j++){
int min[][]={{99999999,-1}};
for(int i=0;i<dist.length;i++){
if(fina[i]==false){
if(min[0][0]>dist[i]){
min[0][0]=dist[i];
min[0][1]=i;
}
}
}
fina[min[0][1]]=true;
//从最短路径出手,找到相连的节点,重新计算最小值
for(Mapnode i:list.get(min[0][1]).outlist){
if(min[0][0]+Adjacency[min[0][1]][(int)i.name.charAt(1)-48]<dist[(int)i.name.charAt(1)-48]){
dist[(int)i.name.charAt(1)-48]=min[0][0]+Adjacency[min[0][1]][(int)i.name.charAt(1)-48];
path[(int)i.name.charAt(1)-48]=min[0][1];
}
}
}
for(int i=0;i<path.length;i++){
System.out.println(list.get(i).name+" "+fina[i]+" "+dist[i]+" "+path[i]);
}
//成功了,迪杰斯特拉nb,总结一下,本算法只适用于权值全为正数的找最短路径算法
}
看最后输出结果对比,谁的视频不用说了吧(,完全一致
最后博主想说的是缔结斯特拉算法只适用于权值为正的找最短路径问题,要是为负的话,需要Bellman-Ford算法,浏览多的话之后博主也会出的