迪杰斯特拉算法优化(dijkstra)

dijkstra常规实现方式:迪杰斯特拉算法(dijkstra)https://blog.csdn.net/weixin_48898946/article/details/120990493

这里主要通过邻接表和优先队列进行优化。

目录

优化点一:

图的存储结构:(邻接表)

邻接表存储思路:

创建图:(以邻接表形式)

核心代码:

遍历邻接表:

java邻接表代码:

程序输出:

优化点二:

优先队列:

dijkstra应用优先队列:

思路:

核心代码:

总的优化后的dijkstra代码:

程序输出:


优化点一:

图的存储结构:(邻接表)

邻接表是数组加链表的存储方式,需要三个类实现:

  • 边类:ArcNode,有三个属性:边指向的顶点的索引,边的权值,指向ArcNode的next指针。
  • 顶点类:VerNode:有两个属性:顶点信息,指向ArcNode的next指针。
  • 图类:AdjGraph:主要属性有:VerNode[]用来存储各顶点,还有一些辅助数组。

邻接表存储思路:

通过用数组(VerNode结点)代表图中各顶点,其next指针指向该顶点的所有出度,即直接相邻的边(ArcNode结点),最后在图类中将顶点(VerNode)存储成数组形式统一保存。

创建图:(以邻接表形式)

思路:头插法:在遍历邻接矩阵时,将所有与某顶点有出度的点插入头结点的后面。先处理待插入结点的next指向头结点的next,再将头结点的next改为待插结点。

核心代码:

public void createGraph() {//构造图
	ArcNode nodeTemp;
	System.out.println("图的邻接表为:");
	for(int i = 0; i < n;i++) {
		for(int j = n - 1; j >= 0;j--) {
			if(edge[i][j] != INF) {
				nodeTemp = new ArcNode(j, edge[i][j]);
				nodeTemp.next = node[i].next;//头插法
				node[i].next = nodeTemp;
			}
		}
	}
}

遍历邻接表:

思路:通过图中的ArcNode数组找出“首结点”,再通过while循环,输出邻接点,直到为null。

public void printGraph() {//打印邻接表
	for(int i = 0; i < n;i++) {
		System.out.printf("%c -> ",vertex[i]);
		ArcNode nodeTemp = node[i].next;
		while(nodeTemp != null) {
			System.out.printf("%c -> ",vertex[nodeTemp.index]);
			nodeTemp = nodeTemp.next;
		}
		System.out.println("^");
	}
}

java邻接表代码:

import java.util.*;

public class Dijkstra {//主类(测试类)
	public static void main(String[] args) {
		final int INF = 0x3f3f3f3f;
		char[]vertex = {'A','B','C','D','E','F','G'};
		int [][]edge = new int [][] {
			{INF,5,7,INF,INF,INF,2},
			{5,INF,INF,9,INF,INF,3},
			{7,INF,INF,INF,8,INF,INF},
			{INF,9,INF,INF,INF,4,INF},
			{INF,INF,8,INF,INF,5,4},
			{INF,INF,INF,4,5,INF,6},
			{2,3,INF,INF,4,6,INF}
		};
		AdjGraph graph = new AdjGraph(edge, vertex);
		graph.createGraph();
		graph.printGraph();
	}
}

class VerNode{//顶点类
	int index;
	ArcNode next;
}

class ArcNode{//边类
	int index;
	int weight;
	ArcNode next;
	
	public ArcNode(int index, int weight) {
		this.index = index;
		this.weight = weight;
	}
}

class AdjGraph{//图类
	final int INF = 0x3f3f3f3f;
	VerNode []node;
	int [][]edge;
	char []vertex;
	int n;//顶点的数量
	
	public AdjGraph(int[][] edge, char[] vertex) {
		n = vertex.length;
		this.edge = edge;
		this.vertex = vertex;
		node = new VerNode[n];
		for(int i = 0; i < n;i++) {
			node[i] = new VerNode();
		}
	}
	
	public void createGraph() {//构造图
		ArcNode nodeTemp;
		System.out.println("图的邻接表为:");
		for(int i = 0; i < n;i++) {
			for(int j = n - 1; j >= 0;j--) {
				if(edge[i][j] != INF) {
					nodeTemp = new ArcNode(j, edge[i][j]);
					nodeTemp.next = node[i].next;
					node[i].next = nodeTemp;
				}
			}
		}
	}
	
	public void printGraph() {//打印邻接表
		for(int i = 0; i < n;i++) {
			System.out.printf("%c -> ",vertex[i]);
			ArcNode nodeTemp = node[i].next;
			while(nodeTemp != null) {
				System.out.printf("%c -> ",vertex[nodeTemp.index]);
				nodeTemp = nodeTemp.next;
			}
			System.out.println("^");
		}
	}
}

程序输出:

图的邻接表为:
A -> B -> C -> G -> ^
B -> A -> D -> G -> ^
C -> A -> E -> ^
D -> B -> F -> ^
E -> C -> F -> G -> ^
F -> D -> E -> G -> ^
G -> A -> B -> E -> F -> ^

优化点二:

优先队列:

优先队列就是制定队列中元素的优先级,优先级越大越优先出队,区别于普通队列的按先后顺序出队。优先队列按照根的大小分为大根堆和小根堆,大根堆是指元素越大越优先出队(即元素越大优先级越高),小根堆反之。

在java中创建优先队列可用 PriorityQueue<>(),默认为从小到大自然排序。

要想按指定方式进行排序,需要将比较器放入参数中,

即 PriorityQueue<>(Comparetor <> comparetor)

优先队列本质是堆的实现,所以进队和出队的时间复杂度均为O(logn)。

dijkstra应用优先队列:

思路:

通过将结点索引和距单源点的距离设置成类,每次在动态更新距离时都 new 出该类的对象加入优先队列中,在造出比较器对象并将其置于参数内后,每次出队都是按设置的优先级出队。

核心代码:

class Node{//优先队列中结点类
	int distance;
	int i;
	
	public Node(int distance, int i) {
		this.distance = distance;
		this.i = i;
	}
}

public void dijkstra(int index) {
	Comparator<Node> comparator = new Comparator<Node>() {
		@Override
		public int compare(Node o1, Node o2) {
			return o1.distance - o2.distance;
		}
	};
	PriorityQueue<Node> pq = new PriorityQueue<>(comparator);

    ...............
}

总的优化后的dijkstra代码:

import java.util.*;

public class Dijkstra {//主类(测试类)
	public static void main(String[] args) {
		final int INF = 0x3f3f3f3f;
		char[]vertex = {'A','B','C','D','E','F','G'};
		int [][]edge = new int [][] {
			{INF,5,7,INF,INF,INF,2},
			{5,INF,INF,9,INF,INF,3},
			{7,INF,INF,INF,8,INF,INF},
			{INF,9,INF,INF,INF,4,INF},
			{INF,INF,8,INF,INF,5,4},
			{INF,INF,INF,4,5,INF,6},
			{2,3,INF,INF,4,6,INF}
		};
		AdjGraph graph = new AdjGraph(edge, vertex);
		graph.createGraph();
		graph.printGraph();
		graph.dijkstra(6);
		graph.getPath(6);
	}
}

class VerNode{//顶点类
	int index;
	ArcNode next;
}

class ArcNode{//边类
	int index;
	int weight;
	ArcNode next;
	
	public ArcNode(int index, int weight) {
		this.index = index;
		this.weight = weight;
	}
}

class Node{//优先队列中结点类
	int distance;
	int i;
	
	public Node(int distance, int i) {
		this.distance = distance;
		this.i = i;
	}
}

class AdjGraph{//图类
	final int INF = 0x3f3f3f3f;
	VerNode []node;
	int [][]edge;
	char []vertex;
	int n;//顶点的数量
	boolean visited[];
	int distance[];
	int prePath[];
	
	public AdjGraph(int[][] edge, char[] vertex) {
		n = vertex.length;
		this.edge = edge;
		this.vertex = vertex;
		node = new VerNode[n];
		for(int i = 0; i < n;i++) {
			node[i] = new VerNode();
		}
		visited = new boolean[n];
		distance = new int [n];
		prePath = new int[n];
	}
	
	public void createGraph() {//构造图
		ArcNode nodeTemp;
		System.out.println("图的邻接表为:");
		for(int i = 0; i < n;i++) {
			for(int j = n - 1; j >= 0;j--) {
				if(edge[i][j] != INF) {
					nodeTemp = new ArcNode(j, edge[i][j]);
					nodeTemp.next = node[i].next;
					node[i].next = nodeTemp;
				}
			}
		}
	}
	
	public void printGraph() {//打印邻接表
		for(int i = 0; i < n;i++) {
			System.out.printf("%c -> ",vertex[i]);
			ArcNode nodeTemp = node[i].next;
			while(nodeTemp != null) {
				System.out.printf("%c -> ",vertex[nodeTemp.index]);
				nodeTemp = nodeTemp.next;
			}
			System.out.println("^");
		}
	}
	
	public void dijkstra(int index) {
		Comparator<Node> comparator = new Comparator<Node>() {
			@Override
			public int compare(Node o1, Node o2) {
				return o1.distance - o2.distance;
			}
		};
		PriorityQueue<Node> pq = new PriorityQueue<>(comparator);
		for(int i = 0; i < n;i++) {
			distance[i] = INF;
			prePath[i] = -1;
		}
		ArcNode t = node[index].next;
		while(t != null) {
			distance[t.index] = t.weight;
			prePath[t.index] = index;
			pq.offer(new Node(t.weight,t.index));
			t = t.next;
		}
		visited[index] = true;
		
		for(int i = 1; i < n;i++) {
			Node temp = pq.poll();//最短距离
			if(visited[temp.i])continue;
			int des = temp.i;
			visited[des] = true;
			
			ArcNode  p = node[des].next;
			while(p != null) {//更新距离
				int len = distance[des] + p.weight;
				if(len < INF && len < distance[p.index]) {
					distance[p.index] = len;
					prePath[p.index] = temp.i;
					pq.offer(new Node(len,p.index));
				}
				p =p.next;
			}
		}
		
		System.out.printf("\n顶点%c到其余各点的距离是:\n",vertex[index]);
		for(int i = 0; i < n;i++) {
			if(i == index)continue;
			System.out.printf("顶点%c到顶点%c的距离是%d米\n",vertex[index],vertex[i],distance[i]);
		}
		System.out.println();
	}
	
	public void getPath(int index) {
		int []temp = new int[n];
		System.out.printf("顶点%c到其余各顶点的路径为:\n",vertex[index]);
		for(int i = 0; i < n;i++) {
			Arrays.fill(temp, 0);
			int t = 0;
			if(i == index)continue;
			temp[t++] = i;
			int f = i;
			f = prePath[f];
			while(true) {
				if(f == index || f == -1)break;
				temp[t++] = f;
				f = prePath[f];
			}
			temp[t] = index;
			System.out.printf("顶点%c到顶点%c的路径为:",vertex[index],vertex[i]);
			for(int j = t;j >= 0; j--) {
				System.out.printf("%c ",vertex[temp[j]]);
			}
			System.out.println();
		}
	}
}

程序输出:

图的邻接表为:
A -> B -> C -> G -> ^
B -> A -> D -> G -> ^
C -> A -> E -> ^
D -> B -> F -> ^
E -> C -> F -> G -> ^
F -> D -> E -> G -> ^
G -> A -> B -> E -> F -> ^

顶点G到其余各点的距离是:
顶点G到顶点A的距离是2米
顶点G到顶点B的距离是3米
顶点G到顶点C的距离是9米
顶点G到顶点D的距离是10米
顶点G到顶点E的距离是4米
顶点G到顶点F的距离是6米

顶点G到其余各顶点的路径为:
顶点G到顶点A的路径为:G A 
顶点G到顶点B的路径为:G B 
顶点G到顶点C的路径为:G A C 
顶点G到顶点D的路径为:G F D 
顶点G到顶点E的路径为:G E 
顶点G到顶点F的路径为:G F 
  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
迪杰斯特拉算法Dijkstra's algorithm)是一种用于求解单源最短路径问题的算法。它可以找到从一个顶点到其他所有顶点的最短路径。 以下是迪杰斯特拉算法的基本步骤: 1. 创建一个空的距离字典,用于存储每个顶点到起始顶点的距离。将起始顶点的距离设置为0,其他顶点的距离设置为无穷大。 2. 创建一个空的已访问集合,用于存储已经找到最短路径的顶点。 3. 重复以下步骤,直到所有顶点都被访问: a. 从未访问的顶点中选择距离起始顶点最近的顶点,并将其添加到已访问集合中。 b. 更新与该顶点相邻的顶点的距离。如果通过当前顶点到达相邻顶点的路径比之前计算的路径更短,则更新距离字典中的值。 4. 最终,距离字典中存储了从起始顶点到每个顶点的最短路径。 以下是一个使用Python实现迪杰斯特拉算法的示例代码: ```python import sys def dijkstra(graph, start): # 初始化距离字典 distances = {vertex: sys.maxsize for vertex in graph} distances[start] = 0 # 初始化已访问集合 visited = set() while len(visited) < len(graph): # 选择距离最小的顶点 min_distance = sys.maxsize min_vertex = None for vertex in graph: if vertex not in visited and distances[vertex] < min_distance: min_distance = distances[vertex] min_vertex = vertex # 将选中的顶点添加到已访问集合中 visited.add(min_vertex) # 更新与选中顶点相邻的顶点的距离 for neighbor, weight in graph[min_vertex].items(): new_distance = distances[min_vertex] + weight if new_distance < distances[neighbor]: distances[neighbor] = new_distance return distances # 示例图的邻接表表示 graph = { 'A': {'B': 5, 'C': 3}, 'B': {'A': 5, 'C': 1, 'D': 3}, 'C': {'A': 3, 'B': 1, 'D': 2, 'E': 6}, 'D': {'B': 3, 'C': 2, 'E': 4, 'F': 2}, 'E': {'C': 6, 'D': 4, 'F': 6}, 'F': {'D': 2, 'E': 6} } start_vertex = 'A' distances = dijkstra(graph, start_vertex) for vertex, distance in distances.items(): print(f"从顶点 {start_vertex} 到顶点 {vertex} 的最短距离为 {distance}") ``` 这段代码实现了迪杰斯特拉算法,通过邻接表表示图,并计算从起始顶点到其他顶点的最短距离。你可以根据自己的需求修改图的表示和起始顶点。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值