持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第八天,点击查看活动详情。
最近在看左神的数据结构与算法,考虑到视频讲的内容和给出的资料的PDF有些出入,不方便去复习,打算出一个左神的数据结构与算法的笔记系列供大家复习,同时也可以加深自己对于这些知识的掌握,该系列以视频的集数为分隔,今天是第六篇:P9|详解前缀树和贪心算法
六、Prim算法
1、实现思路
- 首先随机选定一个结点作为最小生成树的起始结点
- 然后获取该结点连接的边,找到权重最小的边,加入到最小生成树中,同时也要判断是否成环,如果成环就要跳过这个边
2、图解举例
3、实现代码
public static int prim(int[][] graph) {
int size = graph.length;
int[] distances = new int[size];
boolean[] visit = new boolean[size];
visit[0] = true;
for (int i = 0; i < size; i++) {
distances[i] = graph[0][i];
}
int sum = 0;
for (int i = 1; i < size; i++) {
int minPath = Integer.MAX_VALUE;
int minIndex = -1;
for (int j = 0; j < size; j++) {
if (!visit[j] && distances[j] < minPath) {
minPath = distances[j];
minIndex = j;
}
}
if (minIndex == -1) {
return sum;
}
visit[minIndex] = true;
sum += minPath;
for (int j = 0; j < size; j++) {
if (!visit[j] && distances[j] > graph[minIndex][j]) {
distances[j] = graph[minIndex][j];
}
}
}
return sum;
}
- 上述
graph[i][j]表示i与j结点的距离 - 首先选取起始
结点0,然后使用distance[]记录0结点到各个结点的距离 - 同时使用
visit标记结点0已经被访问过了 - 选取
distance中最小的值,同时要保证该值没有被访问过(不成环) - 选中之后,让选中的结点的
visit标记它被访问了 - 然后要重新选定
distance的值,但是值得注意的是,此时只有小于原本distance的值,并且该结点值没有被访问,同时满足这两个条件的值才会放进distance中
3、Prim & Kruskal
- Prim算法需要进行遍历依次寻找邻边的最小值,进行多次比较;而Kruskal算法是需要对权重进行排序,即只需要对权重进行一次排序。
- 不难发现,Kruskal 在算法效率上比 Prim 快
- Kruskal 算法虽然是一个一个来,但是是按照边的权重依次来的,有可能产生两个独立的集合
- 而 Prim 算法按照点一次来,就不会产生两个独立的集合
七、Dijkastra算法
1、实现思路
- Dijkstra算法算是贪心思想实现的
- 首先把起点到所有点的距离存下来找个最短的,然后松弛一次再找出最短的
- 所谓的松弛操作就是,遍历一遍看通过刚刚找到的距离最短的点作为中转站会不会更近,如果更近了就更新距离
- 这样把所有的点找遍之后就存下了起点到其他所有点的最短距离
2、图解分析
- 对于该图,我们得到的理想数据是:
- 到结点②的最短路径为5
- 到结点③的最短路径为4
- 到结点④的最短路径为11
- 到结点⑤的最短路径为11
2. 起始时,使用一个HashMap记录结点到起始点的距离。即 Key 表示 该结点,value 表示 距离。对于没有记录的就是无穷大,即无法到达。
3. 选定最小的结点,即结点1,计算相邻的边,如果计算出来后,该结点不存在于HashMap中就加入,此处就加入了结点②、③、④。同时结点作为已选择的结点存入HashSet。
4. 在选定的结点以外的结点中,选择最小的路径的结点,结点③,此时结点③就确定下来,放进HashSet中,同时计算通过结点③到其他结点的距离,如果有更小的距离就做更新:
1. 到结点②的距离为:4+2=6>5 不做更新
2. 到结点④的距离为:4+7=11<12 更新
3. 到结点⑤的距离为:4+11=15 原本不存在该值,存入HashMap中
5. 在结点①、③之外的结点中选定一个值最小的结点,结点②,此时结点②也确定下来,放进HashSet中,同时计算通过结点②到其他结点的距离,如果有更小的就做更新:
1. 到结点⑤的距离为:5+6=11<15 更新
6. 最后两个结点同理,得到最后的结果:
3、代码实现
public static HashMap<Node, Integer> Dijkstra(Node head) {
HashMap<Node, Integer> distanceMap = new HashMap<>();
distanceMap.put(head, 0);
HashSet<Node> selectedNodes = new HashSet<>();
Node minNode = getMinDistanceAndUnselectedNode(distanceMap, selectedNodes);
while (minNode != null) {
int distance = distanceMap.get(minNode);
for (Edge edge : minNode.edges) {
Node toNode = edge.to;
if (!distanceMap.containsKey(toNode)) {
distanceMap.put(toNode, distance + edge.weight);
}
distanceMap.put(edge.to, Math.min(distanceMap.get(toNode), distance + edge.weight));
}
selectedNodes.add(minNode);
minNode = getMinDistanceAndUnselectedNode(distanceMap, selectedNodes);
}
return distanceMap;
}
public static Node getMinDistanceAndUnselectedNode(HashMap<Node, Integer> distanceMap,
HashSet<Node> touchedNodes) {
Node minNode = null;
int minDistance = Integer.MAX_VALUE;
for (Entry<Node, Integer> entry : distanceMap.entrySet()) {
Node node = entry.getKey();
int distance = entry.getValue();
if (!touchedNodes.contains(node) && distance < minDistance) {
minNode = node;
minDistance = distance;
}
}
return minNode;
}