22.1.13 图

22.1.13 图

1.图的表示方法

  • 常见的有邻接表法,邻接矩阵,数组表示的方法

  • 数组表示的方法:

    例如:一个二维数组为{{1,2,3},{2,4,2},{4,5,1},{2,3,4}},他表示从第一个节点到第二个节点之间有一条长度为3的路,第二个节点到第四个节点之间有一条长度为2的路.......

2.图的常用构造方法

  • code:

    public static class Edge//边集
{
public int weight;//权重
public Node from;//边的开始节点
public Node to;//边的结束节点

public Edge(int weight,Node from,Node to)
{
this.from = from;
this.to = to;
this.weight = weight;
}
}

public static class Node
{
public int value;//图的节点的值
public int in;//节点的入度
public int out;//节点的出度
public ArrayList<Node> nexts;//与某个节点有关的节点
public ArrayList<Edge> edges;//与某个节点有关的边

public Node(int value)
{
this.value = value;
in = 0;
out = 0;
nexts = new ArrayList<>();
edges = new ArrayList<>();
}
}

public static class Graph
{
public HashMap<Integer,Node> nodes;
public HashSet<Edge> edges;

public Graph()
{
nodes = new HashMap<>();
edges = new HashSet<>();
}
}

public static Graph CreatGraph(Integer[][] matrix)
{
Graph graph = new Graph();
for(int i = 0;i<matrix.length;i++)
{
Integer from = matrix[i][0];
Integer to = matrix[i][1];
Integer weight = matrix[i][2];

if(!graph.nodes.containsKey(from))
graph.nodes.put(from, new Node(from));
if(!graph.nodes.containsKey(to))
graph.nodes.put(from, new Node(to));

Node fromNode = graph.nodes.get(from);
Node toNode = graph.nodes.get(to);
Edge newEdge = new Edge(weight,fromNode,toNode);
fromNode.nexts.add(toNode);
fromNode.out++;
toNode.in++;
fromNode.edges.add(newEdge);
graph.edges.add(newEdge);
}
return graph;
}

3.图的遍历

(1)宽度优先dfs
  • 先遍历完一个节点的所有下一个节点,在遍历其中一个子节点的所有下一个节点。

  • code:

public static void bfs(Node node)
//宽度优先遍历
{
if(node == null)
return;
Queue<Node> queue = new LinkedList<>();
HashSet<Node> set = new HashSet<>();
queue.add(node);
set.add(node);
while(!queue.isEmpty())
{
Node cur = queue.poll();
System.out.println(cur.value);
for(Node next:cur.nexts)
{
if(!set.contains(next))
{
set.add(next);
queue.add(next);
}
}
}
}
(2) 深度优先遍历dfs
  • 沿着节点依次走到底,

  • code:

    public static void dfs(Node node) 
{
if(node == null)
return ;
Stack<Node> stack = new Stack<>();
HashSet<Node> set = new HashSet<>();
stack.add(node);
set.add(node);

System.out.println(node.value) ;
while(!stack.isEmpty())
{
Node cur = stack.pop();
for(Node next:cur.nexts)
{
if(!set.contains(next))
{
stack.push(cur);
stack.push(next);
set.add(next);
System.out.println(next.value);
break;
}
}
}
}

4.拓扑排序

  • 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序

  • 规则:

    • 图中的每个顶点只出现一次;

    • A在B前面,则不存在B在A前面的路径。(不能成环!!!!);

    • 顶点的顺序是保证所有指向它的下个节点在被指节点前面!(例如A—>B—>C那么A一定在B前面,B一定在C前面)。所以,这个核心规则下只要满足即可,所以拓扑排序序列不一定唯一

  • 正常步骤为(方法不一定唯一)

    • 从有向无环图中找到一个没有前驱的顶点输出。(可以遍历,也可以用优先队列维护)

    • 删除以这个点为起点的边。(它的指向的边删除,为了找到下个没有前驱的顶点)

    • 重复上述,直到最后一个顶点被输出。如果还有顶点未被输出,则说明有环!

  • code:

    public static List<Node> sortedTopllogy(Graph graph)
{
HashMap<Node,Integer> inMap = new HashMap<>();
//key为某一个节点的node,value为剩余的入度
Queue<Node> zeroInQueue = new LinkedList<>();
//入度为0的节点才能进入这个队列
for(Node node : graph.nodes.values())
{
inMap.put(node, node.in);
if(node.in == 0)
zeroInQueue.add(node);
}
//拓扑排序的结果依次加入result。
List<Node> result = new ArrayList<>();
while(!zeroInQueue.isEmpty())
{
Node cur = zeroInQueue.poll();
result.add(cur);
for(Node next : cur.nexts)
{
inMap.put(next, inMap.get(next)-1);
if(inMap.get(next) == 0)
zeroInQueue.add(next);
}
}
return result;
}

5.生产最小生成树

(1)k算法:
  • 加边,依次加最小边,如果形成环就不加反之则加。

  • code:

    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 cur: toSet)
{
fromSet.add(cur);
setMap.put(cur, fromSet);
}
}
}
(2) prime算法
  • 加点法:任意取一个点,从与这个点相关的边中选取最小的一个边,把通过这个最小边相连的点加入。

  • code:

public static class EdgeComparator implements Comparator<Edge>
{
   public int cimpare(Edge o1,Edge 02)
  {
       return 01.weight - o2.weight;
  }
}
//比较器

public static Set<Edge> primMST(Graph graph)
{
   PriorityQueue<Edge> priorityQueue  = new PriorityQueue<>(new EdgeComparator());
   //小的进入集合
   HashSet<Node> set = new HashSet<>();
   
   Set<Edge> result = new HashSet<>();
   //存储最后结果的点集
   
   for(Node node : graph.notes.values())//防止森林中的多个不连通的图
  {
       if(!set.contains(node))
      {
           ste.add(node);
           for(Edge edge : node.edges)
          {
               priorityQueue.add(edge);
          }
           while (!prioritoyQueue.isEmpty())
          {
               Edge edge = priorityQueue.poll();
               //弹出最小的边
               Node toNode = edge.to;
               //可能的一个新的点
               if(!set.comtains(toNode))//集合中不含有这个点就是一个新的点
              {
                   set.add(toNode);
                   result.add(edge);
                   for(Edge nextEdge : toNode.edges)
                  {
                       priorityQueue.add(nextEdge);
                  }
              }
          }
      }
  }
}

6 Dijkstra算法(适用于没有权值为负数的边,解决单源最短路径问题)

  • Dijkstra提出按各顶点与源点v间的路径长度的递增次序,生成到各顶点的最短路径的算法。即先求出长度最短的一条最短路径,再参照它求出长度次短的一条最短路径,依次类推,直到从源点v 到其它各顶点的最短路径全部求出为止。

  • code:

    public static HashMap<Node, Integer> dijkstra1(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;
}

 

posted @ 2022-01-14 17:54  张满月。  阅读(51)  评论(0编辑  收藏  举报