# 图论 图论算法可以说是在数据结构中有着极其重要的存在,它的算法都不难理解,主要是如何去存储这个图结构
图结构
通常采用二维数组的方式存储
也可以采用一维数组存储 代码表示如下 点集 边集
经典算法
BFS(宽度优先遍历)
BFS也称宽度优先遍历,即一层一层的遍历,相对于DFS(深度优先遍历),用到了队列的结构。宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。
DFS(深度优先便利)
DFS也称深度优先遍历,就是一条路走到黑,遇到能走的就一直走
拓扑排序
拓扑排序就是每一步都要由上一步作为条件,才能走到下一步,适合用于工程算法
如下图,走到B必须完成A,算法的关键:完成一步,把完成的节点删除掉,并且把和这个节点有关的依赖都删掉,例如:删掉A,把关于A的依赖都删除掉
克鲁斯卡尔算法(Kruskal)
用于最小生成树(就是边权最小的树)的算法,也称K算法(适用于无向图)
- setMap用于存储一个点的信息,包括该点和该点连接下一节点的集合
- isSameSet用于判断fromSet和toSet是不是来自一个集合,用于判断会不会形成环
- union用于合并from和to
K算法主函数
public static class MySets{
public HashMap<Node, List<Node>> setMap;
public MySets(List<Node> nodes){
for(Node cur : nodes){
List<Node> set = new ArrayList<Node>();
set.add(cur);
setMap.put(cur,set);
}
}
public boolean isSameSet(Node from,Node to){
List<Node> fromSet = setMap.get(from);
List<Node> toSet = setMap.get(to);
return fromSet == toSet;
}
public void union(Node from,Node to){
List<Node> fromSet = setMap.get(from);
List<Node> toSet = setMap.get(to);
for(Node toNode : toSet){
fromSet.add(toNode);
setMap.put(toNode,fromSet);
}
}
public static class EdgeComparator implements Comparator<Edge> {
@Override
public int compara(Edge o1,Edge o2){
return o1.weight-o2.weight;
}
}
public static Set<Edge> kruskalMST(Graph graph){
MySets mysets = new MySets(graph.nodes.values());
PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new EdgeComparator());
for(Edge edge : graph.edges){
priorityQueue.add(edge);
}
Set<Edge> result = new HashSet<>();
while(!priorityQueue.isEmpty()){
Edge edge = priorityQueue.poll();
if(!mysets.isSameSet(edge.from,edge.to)){
result.add(edge);
mysets.union(edge.from,edge.to);
}
}
return result;
}
}
下面是并查集版本
P算法(Prim算法)
P算法也称Prim算法,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。
public static class EdgeComparator implements Comparator<Edge>{
@Override
public int compara(Edge o1,Edge o2){
return o1.weight-o2.weight;
}
}
public static Set<Edge> primMST(Graph graph){
PriorityQueue<Edge> priortyQueue = new PriorityQueue<>(new
EdgeComparator());
HashSet<Node> set = new HashSet<>();
Set<Edge> result = new HashSet<>();
for(Node node : graph.nodes.values()){
if(!set.contains(node)){
set.add(node);
for(Edge edge : node.edges){
priorityQueue.add(edge);
}
while(!priorityQueue.isEmpty()){
Edge edge = priorityQueue.poll();
Node toNode = edge.to;
if(!set.contains(toNode)){
set.add(toNode);
result.add(edge);
for(Edge nextEdge : toNode.edges){
priorityQueue.add(nextEdge);
}
}
}
}
return result;
}
Dijkstra算法
如下图,选A作为出发点,除了A到A距离是0,别的点都设为无穷大,然后找到与A相连的其余节点,根据权重来更新距离,之后选择一个权重最小的边,把A标记上并且封锁,如下图我们可以找到B是权重较小的一个节点,下一次从B开始,循环往复,直到全部的点都封锁
public static HashMap<Node,Integer> dijkstra(Node node){
HashMap<Node, Integer> distanceMap = new HashMap<>();
distanceMap.put(head,0);
HashSet<Node> selectedNodes = new HashSet<>();
Node minNode = getMinDistanceAndUnselectedNode(distanceMap, selectedMap);
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 = getMinDistanceAndUnseletedNode(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> : distanceMap.entrySet()){
Node node = entry.getKey();
int distance = entry.getValue();
if(!touchedNodes.contains(node) && disatance < minDistance){
minNode = node;
minDistance = distance;
}
}
return minNode;
}
结语
对以上算法有问题的朋友欢迎在评论区发言,觉得不错还请各位点赞支持
|