算法体系-17 第十七节 图 (20节)

一 图的概念

1)由点的集合和边的集合构成

2)虽然存在有向图和无向图的概念,但实际上都可以用有向图来表达

3)边上可能带有权值

二 图结构的表达

1)邻接表法

2)邻接矩阵法

3)除此之外还有其他众多的方式 一个边一个边的人给你

2.1 邻接表法

2.2 邻接矩阵法

面试中经常遇到的 一个一个边给你

【3,0 ,7 】 0到7 权重3

三、 图的面试题如何搞定

图的算法都不算难,只不过coding的代价比较高

1)先用自己最熟练的方式,实现图结构的表达

2)在自己熟悉的结构上,实现所有常用的图算法作为模板

3)把面试题提供的图结构转化为自己熟悉的图结构,再调用模板或改写即可

四 、图的转化器

图的转换器 GraphGenerator

4.1 代码

import java.util.HashMap;
import java.util.HashSet;
//图由点集和边集组成
public class Graph {
    //点集 整数就是当前的数值,node对应数值生成的node
    public HashMap<Integer, Node> nodes;
 //边集
    public HashSet<Edge> edges;
    
    public Graph() {
        nodes = new HashMap<>();
        edges = new HashSet<>();
    }
}

package class16;

public class Edge {
    //权重
    public int weight;
 //从哪个点
    public Node from;
 //到哪个点
    public Node to;

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

}

package class16;

import java.util.ArrayList;

// 点结构的描述
public 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 class GraphGenerator {

    // matrix 所有的边
    // N*3 的矩阵
    // [weight, from节点上面的值,to节点上面的值]
    // 
    // [ 5 , 0 , 7]
    // [ 3 , 0,  1]
    // 
 //三条边
 [
 [ 5 , 0 , 7],
 [ 5 , 0 , 7],
 [ 5 , 0 , 7]
 ]
    public static Graph createGraph(int[][] matrix) {
        Graph graph = new Graph();
        for (int i = 0; i < matrix.length; i++) {
             // 拿到每一条边, matrix[i] 
            int weight = matrix[i][0];
            int from = matrix[i][1];
            int to = matrix[i][2];
            if (!graph.nodes.containsKey(from)) {
                graph.nodes.put(from, new Node(from));
            }
            if (!graph.nodes.containsKey(to)) {
                graph.nodes.put(to, 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;
    }

}

五、 图的宽度优先&深度优先遍历

5.1 图的宽度优先分析

描述 -宽度优先遍历

1,利用队列实现

2,从源节点开始依次按照宽度进队列,然后弹出

3,每弹出一个点,把该节点所有没有进过队列的邻接点放入队列

4,直到队列变空

为哈要加set 因为图是有回路的,如果没有set判断某个节点是否打印过,就会出现循环打印的情况,没完没了

5.2 代码

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;

public class Code01_BFS {

    // 从node出发,进行宽度优先遍历
    public static void bfs(Node start) {
        if (start == null) {
            return;
        }
        Queue<Node> queue = new LinkedList<>();
        HashSet<Node> set = new HashSet<>();
        queue.add(start);
        set.add(start);
        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);
                }
            }
        }
    }

}

import java.util.*;
class Graph {
    private int V; // 图中节点数量
    private LinkedList<Integer> adj[]; // 存储每个节点相连接的其他节点列表
    
    public Graph(int v) {
        V = v;
        adj = new LinkedList[V];
        
        for (int i=0; i < V; ++i)
            adj[i] = new LinkedList();
    }
    
    public void addEdge(int v, int w) {
        adj[v].add(w);
    }
    
    public void BFS(int s) {
        boolean visited[] = new boolean[V];
        
        Queue<Integer> queue = new LinkedList<>();
        
        visited[s]=true;
        System.out.print("BFS Traversal starting from " + s + ": ");
        queue.add(s);
        
        while (!queue.isEmpty()) {
            s = queue.poll();
            
            Iterator<Integer> i = adj[s].listIterator();
            while (i.hasNext()) {
                int n = i.next();
                
                if (!visited[n]) {
                    visited[n] = true;
                    System.out.print(n + " ");
                    queue.add(n);
                }
            }
        }
    }
}
 
public class Main {
    public static void main(String args[]) {
        Graph g = new Graph(4);
        
        g.addEdge(0, 1);
        g.addEdge(0, 2);
        g.addEdge(1, 3);
        g.addEdge(2, 3);
        
        g.BFS(0);
    }
}

5.3深度优先遍历 分析

set 打印过的节点放到set里面

描述-深度优先遍历 一条路没走完就一直走

1,利用栈实现

2,从源节点开始把节点按照深度放入栈,然后弹出

3,每弹出一个点,把该节点下一个没有进过栈的邻接点放入栈

4,直到栈变空

5.4 代码

package class16;

import java.util.HashSet;
import java.util.Stack;

public class Code02_DFS {

    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;
                }
            }
        }
    }
    

}
   
import java.util.*;
 
class Graph {
    private int V; // 图中节点数量
    private LinkedList<Integer> adj[]; // 存储每个节点相连接的其他节点列表
    
    public Graph(int v) {
        V = v;
        adj = new LinkedList[V];
        
        for (int i=0; i<v; ++i)
            adj[i] = new LinkedList();
    }
    
    public void addEdge(int v, int w) {
        adj[v].add(w);
    }
    
    public void DFSUtil(int v, boolean visited[]) {
        visited[v] = true;
        System.out.print(v + " ");
        
        Iterator<Integer> itr = adj[v].iterator();
        while (itr.hasNext()) {
            int nbr = itr.next();
            
            if (!visited[nbr])
                DFSUtil(nbr, visited);
        }
    }
    
    public void DFSTraversal() {
        boolean[] visited = new boolean[V];
        
        for (int i=0; i<V; ++i)
            visited[i] = false;
        
        for (int i=0; i<V; ++i)
            if (!visited[i])
                DFSUtil(i, visited);
    }
}
 
public class Main {
    public static void main(String args[]) {
        Graph g = new Graph(4);
        
        g.addEdge(0, 1);
        g.addEdge(0, 2);
        g.addEdge(1, 3);
        g.addEdge(2, 3);
        
        System.out.println("DFS Traversal starting from vertex 0");
        g.DFSTraversal();
    }
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值