【Java数据结构】04-图(Prim,Kruskal,Dijkstra,topo)

5 图

推荐辅助理解

  1. 【视频讲解】bilibili
    Dijkstra
    在这里插入图片描述
    Prim
    在这里插入图片描述

  2. 【手动可视化】Algorithm Visualizer (https://algorithm-visualizer.org/)

  3. 【手动可视化】Data Structure Visualizations (https://www.cs.usfca.edu/~galles/visualization/Algorithms.html)

5.1 掌握图的定义,包括完全图、连通图、简单路径、有向图、无向图、无环图等,明确理解图和二叉树、树和森林这种结构之间的异同点

图的基本定义

期末考试选择题中考察了连通分量和子图的区别。
图(Graph)是由节点(Vertex)和边(Edge)组成的一种数据结构,表示节点之间的关系。图分为有向图和无向图,边可以有权重。若图的顶点数为n,则它得生成树含有n-1条边。

  1. 节点(Vertex): 表示图中的一个元素或实体。
  2. 边(Edge): 表示节点之间的关系,可以是有向的或无向的。
  3. 度(Degree): 图中与该点相连的边数

无向图:几条边就是几个度(全部顶点的度的和等于边数的两倍)d=2e
有向图:某顶点的度=出度数+入度数(全部顶点的度=所有顶点出度+入度)
子图:就是一个整图的一部分,但是必须子图也是图。且也就是说边和顶点需要一起出现。

图的分类
  1. 有向图(Directed Graph): 边有方向,从一个节点指向另一个节点。
  2. 无向图(Undirected Graph): 边没有方向,两个节点之间的关系是双向的。
  3. 加权图(Weighted Graph): 边带有权重,表示节点之间的距离或成本。
  4. 无权图(Unweighted Graph): 边没有权重,只表示节点之间的连接关系。
  5. 完全图(Complete Graph): 每一对节点之间都有一条边。
图的连通性
  1. 连通图(Connected Graph): 任意两个节点之间都存在路径,即图中没有孤立的节点。
  2. 非连通图(Disconnected Graph): 存在孤立的节点,有些节点之间没有路径。
图的路径和环
  1. 路径(Path): 由边连接的一系列节点,形成的序列称为路径。
  2. 简单路径(Simple Path): 不经过重复节点的路径。
  3. 环(Cycle): 起点和终点相同的路径。
图与树、森林的异同
  1. 相同点: 图、树和森林都是由节点和边构成的数据结构,表示元素之间的关系。
  2. 不同点:
    • 图 vs 树: 树是一种特殊的无环图,所有节点通过唯一的路径相互连接,并且没有孤立的节点。
    • 图 vs 森林: 森林是多棵树的集合,每棵树都是独立的。

5.2 掌握图采用邻接矩阵和邻接表进行存储的差异性

图可以使用邻接矩阵和邻接表两种方式进行存储,它们各有优缺点,适用于不同的场景。
期末考试有考到把给出的无向图的邻接矩阵写出来

邻接矩阵

邻接矩阵是使用二维数组来表示图的连接关系。对于有向图,矩阵中的元素 a[i][j] 表示从节点 i 到节点 j 是否存在边;对于无向图,矩阵是对称的,a[i][j] = a[j][i]

优点:

  1. 查找边的存在性快速: 直接访问矩阵元素即可确定两个节点之间是否有边。
  2. 适用于稠密图: 当图边比较多时,矩阵存储相对紧凑。

缺点:

  1. 浪费空间: 对于稀疏图,大部分元素为 0,会占用大量空间。
  2. 添加或删除节点麻烦: 需要调整整个矩阵的大小。
邻接表

邻接表是通过链表来表示图的连接关系。对于每个节点,用一个链表存储与它相邻的节点。

优点:

  1. 节省空间: 对于稀疏图,只存储存在边的部分,节省空间。
  2. 添加或删除节点方便: 通过调整链表,添加或删除节点相对方便。

缺点:

  1. 查找边的存在性相对慢: 需要遍历链表来确定两个节点之间是否有边。
  2. 适用于稀疏图: 对于密集图,可能会占用更多的空间。
比较
  1. 空间复杂度: 邻接矩阵通常占用更多的空间,而邻接表对于稀疏图更经济。
  2. 时间复杂度: 邻接矩阵在查找边的存在性上更快,而邻接表在添加或删除节点上更快。
  3. 适用场景: 邻接矩阵适用于稠密图,而邻接表适用于稀疏图。
Java 代码示例
1.邻接矩阵
class GraphMatrix {
    private int[][] matrix;

    public GraphMatrix(int n) {
        matrix = new int[n][n];
    }

    public void addEdge(int i, int j) {
        matrix[i][j] = 1;
        matrix[j][i] = 1; // 对于无向图,设置对称位置的元素
    }

    // 其他操作...
}
2.邻接表
import java.util.LinkedList;

class GraphList {
    private int V;
    private LinkedList<Integer>[] adjList;

    public GraphList(int V) {
        this.V = V;
        adjList = new LinkedList[V];
        for (int i = 0; i < V; ++i) {
            adjList[i] = new LinkedList<>();
        }
    }

    public void addEdge(int i, int j) {
        adjList[i].add(j);
        adjList[j].add(i); // 对于无向图,添加到两个节点的邻接表中
    }

    // 其他操作...
}

5.3 掌握广度优先遍历和深度优先遍历

广度优先遍历(BFS)

广度优先遍历是一种逐层访问图中节点的遍历方法。从起始节点开始,依次访问其所有相邻节点,然后再逐层访问下一层的节点。

算法步骤
  1. 将起始节点放入队列。
  2. 从队列中弹出一个节点,访问该节点并将其所有未访问的相邻节点加入队列。
  3. 重复步骤 2,直到队列为空。
Java 代码示例
import java.util.LinkedList;
import java.util.Queue;

class Graph {
    private int V; // 节点数量
    private LinkedList<Integer>[] adjList;

    public Graph(int V) {
        this.V = V;
        adjList = new LinkedList[V];
        for (int i = 0; i < V; ++i) {
            adjList[i] = new LinkedList<>();
        }
    }

    public void addEdge(int i, int j) {
        adjList[i].add(j);
        adjList[j].add(i); // 对于无向图,添加到两个节点的邻接表中
    }

    public void bfs(int start) {
        boolean[] visited = new boolean[V];
        Queue<Integer> queue = new LinkedList<>();
        visited[start] = true;
        queue.offer(start);

        while (!queue.isEmpty()) {
            int current = queue.poll();
            System.out.print(current + " ");

            for (int neighbor : adjList[current]) {
                if (!visited[neighbor]) {
                    visited[neighbor] = true;
                    queue.offer(neighbor);
                }
            }
        }
    }
}
深度优先遍历(DFS)

深度优先遍历是一种递归或栈的方式遍历图的方法。从起始节点开始,访问一个相邻节点,然后递归或压栈访问该节点的未访问相邻节点,直到没有未访问的相邻节点为止,然后回溯到上一层继续。

算法步骤
  1. 从起始节点开始递归或使用栈,访问该节点并标记为已访问。
  2. 对该节点的未访问相邻节点,递归或压栈访问它们。
  3. 重复步骤 2,直到当前路径上没有未访问的相邻节点。
  4. 回溯到上一层,继续步骤 2。
Java 代码示例
import java.util.LinkedList;
import java.util.Stack;

class Graph {
    private int V; // 节点数量
    private LinkedList<Integer>[] adjList;

    public Graph(int V) {
        this.V = V;
        adjList = new LinkedList[V];
        for (int i = 0; i < V; ++i) {
            adjList[i] = new LinkedList<>();
        }
    }

    public void addEdge(int i, int j) {
        adjList[i].add(j);
        adjList[j].add(i); // 对于无向图,添加到两个节点的邻接表中
    }

    public void dfs(int start) {
        boolean[] visited = new boolean[V];
        dfsRecursive(start, visited);
    }

    private void dfsRecursive(int current, boolean[] visited) {
        visited[current] = true;
        System.out.print(current + " ");

        for (int neighbor : adjList[current]) {
            if (!visited[neighbor]) {
                dfsRecursive(neighbor, visited);
            }
        }
    }
}

5.4 掌握最小生成树(Prim算法、Kruskal算法)、最短路径(Dijkstra算法)、拓扑排序的实现过程

期末考试中,选择题考察了拓扑排序(哪种算法能判断一个图中有没有环),大题中考察了Dijkstra算法(给了有向图写出最短路径,需有过程)

最小生成树

最小生成树(Minimum Spanning Tree,简称 MST)是一个连通图的生成树,其中包含了图中所有的顶点,但是只包含足够的边以使得生成树的总权重最小。两个经典的算法用于找到最小生成树:Prim 算法和 Kruskal 算法。Prim 算法更注重顶点的选择,而 Kruskal 算法更注重边的选择。
动态演示在GreedAlgorithm-prim,kruskal,dijkstra

1. Prim 算法

Prim 算法通过逐步选择连接两棵独立树的最小权重边来构建最小生成树。它始终在当前已选取的顶点集合和未选取的顶点集合之间找到权重最小的边
注:在 Prim 算法中,通常规定图的边的权值不能为0。这是因为 Prim 算法的核心思想是选择具有最小权值的边,然后逐步构建最小生成树。如果存在权值为0的边,它们可能在选择过程中引起混淆。

在这里插入图片描述

Java 代码示例
import java.util.Arrays;

class PrimAlgorithm {
    static final int V = 5;

    int minKey(int key[], boolean mstSet[]) {
        int min = Integer.MAX_VALUE, minIndex = -1;

        for (int v = 0; v < V; v++) {
            if (!mstSet[v] && key[v] < min) {
                min = key[v];
                minIndex = v;
            }
        }

        return minIndex;
    }

    void primMST(int graph[][]) {
        int parent[] = new int[V];
        int key[] = new int[V];
        boolean mstSet[] = new boolean[V];

        Arrays.fill(key, Integer.MAX_VALUE);
        key[0] = 0;
        parent[0] = -1;

        for (int count = 0; count < V - 1; count++) {
            int u = minKey(key, mstSet);
            mstSet[u] = true;

            for (int v = 0; v < V; v++) {
                if (graph[u][v] != 0 && !mstSet[v] && graph[u][v] < key[v]) {
                    parent[v] = u;
                    key[v] = graph[u][v];
                }
            }
        }

        printMST(parent, graph);
    }

    void printMST(int parent[], int graph[][]) {
        System.out.println("Edge \tWeight");
        for (int i = 1; i < V; i++) {
            System.out.println(parent[i] + " - " + i + "\t" + graph[i][parent[i]]);
        }
    }

    public static void main(String[] args) {
        PrimAlgorithm t = new PrimAlgorithm();
        int graph[][] = new int[][]{{0, 2, 0, 6, 0},
                                    {2, 0, 3, 8, 5},
                                    {0, 3, 0, 0, 7},
                                    {6, 8, 0, 0, 9},
                                    {0, 5, 7, 9, 0}};

        t.primMST(graph);
    }
}
2. Kruskal 算法

Kruskal 算法通过按权重递增的顺序选择边来构建最小生成树。它始终选择不形成环路的边,直到构建完整的最小生成树。

在这里插入图片描述

Java 代码示例:
import java.util.Arrays;

class KruskalAlgorithm {
    class Edge implements Comparable<Edge> {
        int src, dest, weight;

        public int compareTo(Edge compareEdge) {
            return this.weight - compareEdge.weight;
        }
    }

    int V, E;
    Edge edge[];

    KruskalAlgorithm(int v, int e) {
        V = v;
        E = e;
        edge = new Edge[E];
        for (int i = 0; i < e; ++i)
            edge[i] = new Edge();
    }

    int find(int parent[], int i) {
        if (parent[i] == -1)
            return i;
        return find(parent, parent[i]);
    }

    void union(int parent[], int x, int y) {
        int xset = find(parent, x);
        int yset = find(parent, y);
        parent[xset] = yset;
    }

    void kruskalMST() {
        Edge result[] = new Edge[V];
        int e = 0;
        int i = 0;
        for (i = 0; i < V; ++i)
            result[i] = new Edge();

        Arrays.sort(edge);

        int parent[] = new int[V];
        Arrays.fill(parent, -1);

        i = 0;

        while (e < V - 1) {
            Edge nextEdge = edge[i++];
            int x = find(parent, nextEdge.src);
            int y = find(parent, nextEdge.dest);

            if (x != y) {
                result[e++] = nextEdge;
                union(parent, x, y);
            }
        }

        System.out.println("Edge \tWeight");
        for (i = 0; i < e; ++i)
            System.out.println(result[i].src + " - " + result[i].dest + "\t" + result[i].weight);
    }

    public static void main(String[] args) {
        int V = 4;
        int E = 5;
        KruskalAlgorithm graph = new KruskalAlgorithm(V, E);

        graph.edge[0].src = 0;
        graph.edge[0].dest = 1;
        graph.edge[0].weight = 10;

        graph.edge[1].src = 0;
        graph.edge[1].dest = 2;
        graph.edge[1].weight = 6;

        graph.edge[2].src = 0;
        graph.edge[2].dest = 3;
        graph.edge[2].weight = 5;

        graph.edge[3].src = 1;
        graph.edge[3].dest = 3;
        graph.edge[3].weight = 15;

        graph.edge[4].src = 2;
        graph.edge[4].dest = 3;
        graph.edge[4].weight = 4;

        graph.kruskalMST();
    }
}
最短路径
Dijkstra 算法

Dijkstra 算法用于找到图中单源最短路径。它从起始节点开始,逐步选择距离最近的节点,并更新到其他节点的最短距离。
在这里插入图片描述

Java 代码示例
import java.util.Arrays;

class DijkstraAlgorithm {
    static final int V = 9;

    int minDistance(int dist[], boolean sptSet[]) {
        int min = Integer.MAX_VALUE, min_index = -1;

        for (int v = 0; v < V; v++) {
            if (!sptSet[v] && dist[v] <= min) {
                min = dist[v];
                min_index = v;
            }
        }

        return min_index;
    }

    void printSolution(int dist[]) {
        System.out.println("Vertex \tDistance from Source");
        for (int i = 0;

 i < V; i++)
            System.out.println(i + " \t" + dist[i]);
    }

    void dijkstra(int graph[][], int src) {
        int dist[] = new int[V];
        boolean sptSet[] = new boolean[V];

        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[src] = 0;

        for (int count = 0; count < V - 1; count++) {
            int u = minDistance(dist, sptSet);
            sptSet[u] = true;

            for (int v = 0; v < V; v++) {
                if (!sptSet[v] && graph[u][v] != 0 && dist[u] != Integer.MAX_VALUE &&
                        dist[u] + graph[u][v] < dist[v]) {
                    dist[v] = dist[u] + graph[u][v];
                }
            }
        }

        printSolution(dist);
    }

    public static void main(String[] args) {
        int graph[][] = new int[][]{{0, 4, 0, 0, 0, 0, 0, 8, 0},
                                    {4, 0, 8, 0, 0, 0, 0, 11, 0},
                                    {0, 8, 0, 7, 0, 4, 0, 0, 2},
                                    {0, 0, 7, 0, 9, 14, 0, 0, 0},
                                    {0, 0, 0, 9, 0, 10, 0, 0, 0},
                                    {0, 0, 4, 14, 10, 0, 2, 0, 0},
                                    {0, 0, 0, 0, 0, 2, 0, 1, 6},
                                    {8, 11, 0, 0, 0, 0, 1, 0, 7},
                                    {0, 0, 2, 0, 0, 0, 6, 7, 0}};

        DijkstraAlgorithm t = new DijkstraAlgorithm();
        t.dijkstra(graph, 0);
    }
}
拓扑排序

拓扑排序用于有向无环图(DAG),它确定图中节点的线性顺序,使得对于每一条有向边 (u, v),节点 u 在拓扑排序中都出现在节点 v 的前面。

Java 代码示例
import java.util.*;

class TopologicalSort {
    private int V;
    private LinkedList<Integer> adj[];

    TopologicalSort(int v) {
        V = v;
        adj = new LinkedList[v];
        for (int i = 0; i < v; ++i)
            adj[i] = new LinkedList();
    }

    void addEdge(int v, int w) {
        adj[v].add(w);
    }

    void topologicalSortUtil(int v, boolean visited[], Stack<Integer> stack) {
        visited[v] = true;
        Integer i;

        Iterator<Integer> it = adj[v].iterator();
        while (it.hasNext()) {
            i = it.next();
            if (!visited[i])
                topologicalSortUtil(i, visited, stack);
        }

        stack.push(v);
    }

    void topologicalSort() {
        Stack<Integer> stack = new Stack<>();

        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])
                topologicalSortUtil(i, visited, stack);

        System.out.println("Topological Sort:");
        while (!stack.empty())
            System.out.print(stack.pop() + " ");
    }

    public static void main(String args[]) {
        TopologicalSort g = new TopologicalSort(6);
        g.addEdge(5, 2);
        g.addEdge(5, 0);
        g.addEdge(4, 0);
        g.addEdge(4, 1);
        g.addEdge(2, 3);
        g.addEdge(3, 1);

        g.topologicalSort();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/327077.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于k8s Deployment的弹性扩缩容及滚动发布机制详解

k8s第一个重要设计思想&#xff1a;控制器模式。k8s里第一个控制器模式的完整实现&#xff1a;Deployment。它实现了k8s一大重要功能&#xff1a;Pod的“水平扩展/收缩”&#xff08;horizontal scaling out/in&#xff09;。该功能从PaaS时代开始就是一个平台级项目必备编排能…

cookie和session的工作过程和作用:弥补http无状态的不足

cookie是客户端浏览器保存服务端数据的一种机制。当通过浏览器去访问服务端时&#xff0c;服务端可以把状态数据以key-value的形式写入到cookie中&#xff0c;存储到浏览器。浏览器下次去服务服务端时&#xff0c;就可以把这些状态数据携带给服务器端&#xff0c;服务器端可以根…

OceanBase架构概览

了解一个系统或软件&#xff0c;比较好的一种方式是了解其架构&#xff0c;下图是官网上的架构图&#xff0c;基于V 4.2.1版本 OceanBase 使用通用服务器硬件&#xff0c;依赖本地存储&#xff0c;分布式部署在多个服务器上&#xff0c;每个服务器都是对等的&#xff0c;数据库…

如何画出优秀的系统架构图-架构师系列-学习总结

--- 后之视今&#xff0c;亦犹今之视昔&#xff01; 目录 早期系统架构图 早期系统架构视图 41视图解读 41架构视图缺点 现代系统架构图的指导实践 业务架构 例子 使用场景 画图技巧 客户端架构、前端架构 例子 使用场景 画图技巧 系统架构 例子 定义 使用场…

Keepalived 双机热备

本章主要内容&#xff1a; Keepalived 双机热备基础知识学会构建双机热备系统学会构建LVSHA 高可用群集 简介 在这个高度信息化的IT时代&#xff0c;企业的生产系统&#xff0c;业务运营&#xff0c;销售和支持&#xff0c;以及日常管理等环节越来越依赖于计算机和服务&#…

class_1:qt的安装及基本使用方式

一、选择组件&#xff1a; 1、windows编译工具&#xff1a;MinGW 7.30 32-bit MinGW 7.30 64-bit 2、QT源代码&#xff1a;sources 3、QT的绘图模块&#xff1a;QT charts 4、QT虚拟键盘&#xff1a;QT Virtual Keyboard 5、QT Creational 4.12.2 GDB 二、新建QT项目 文…

【MATLAB】 HANTS滤波算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 1 基本定义 HANTS滤波算法是一种时间序列谐波分析方法&#xff0c;它综合了平滑和滤波两种方法&#xff0c;能够充分利用遥感图像存在时间性和空间性的特点&#xff0c;将其空间上的分布规律和时间上的变化规律联系起来…

构建 Maven 项目时可能遇到的问题

文章目录 构建 Maven 项目时可能遇到的问题1. Maven 自动下载依赖后&#xff0c;在本地仓库中找不到2. 运行时报错如下&#xff1a;Error: java 不支持发行版本 53. 创建 Maven 项目后 pom.xml 文件为空4. 在 Settings 中 Update 了阿里云远程仓库&#xff0c;导致整个项目不能…

美国智库发布《用人工智能展望网络未来》的解析

文章目录 前言一、人工智能未来可能改善网络安全的方式二、人工智能可能损害网络安全的方式三、人工智能使用的七条建议四、人工智能的应用和有效使用AI五、安全有效地使用人工智能制定具体建议六、展望网络未来的人工智能&#xff08;一&#xff09;提高防御者的效率&#xff…

数据结构学习 jz29 顺时针打印矩阵

关键词&#xff1a;模拟 题目&#xff1a;螺旋遍历二维数组 简单题做了超过40分钟 调了很久 不好 方法一&#xff1a; 我自己做的。 思路&#xff1a; xy_t&#xff1a; 记录xy的方向&#xff0c;往右走&#xff0c;往下走&#xff0c;往左走&#xff0c;往上走 t控制方…

算法第十八天-打家劫舍Ⅱ

打家劫舍Ⅱ 题目要求 解题思路 [打家劫舍Ⅱ]是说两个相邻的房间不能同时偷&#xff0c;并且首尾两个房间是相邻的&#xff08;不能同时偷首尾房间&#xff09;明显是基于[打家劫舍Ⅰ]做的升级。[打家劫舍Ⅰ]也是说两个相邻的房间不能同时偷&#xff0c;但是首尾房间不是相邻的…

Java多线程基础:虚拟线程与平台线程解析

在这篇文章中&#xff0c;主要总结一些关于线程的概念&#xff0c;以及更近期的名为虚拟线程的特性。将了解平台线程和虚拟线程在性质上的区别&#xff0c;以及它们如何促进应用程序性能的改进 经典线程背景&#xff1a; 让我们以调用外部API或某些数据库交互的场景为例&…

JVM篇--Java内存区域高频面试题

java内存区域 1 Java 堆空间及 GC&#xff1f; 首先我们要知道java堆空间的产生过程&#xff1a; 即当通过java命令启动java进程的时候&#xff0c;就会为它分配内存&#xff0c;而分配内存的一部分就会用于创建堆空间&#xff0c;而当程序中创建对象的时候 就会从堆空间来分…

918. 环形子数组的最大和

参考题解&#xff1a;https://leetcode.cn/problems/maximum-sum-circular-subarray/solutions/1152143/wo-hua-yi-bian-jiu-kan-dong-de-ti-jie-ni-892u/ class Solution {public int maxSubarraySumCircular(int[] nums) {int n nums.length;int sum nums[0], minSum nums…

【目标跟踪】跨相机如何匹配像素

文章目录 前言一、计算思路二、代码三、结果 前言 本本篇博客介绍一种非常简单粗暴的方法&#xff0c;做到跨相机像素匹配。已知各相机内外参&#xff0c;计算共视区域像素投影&#xff08;不需要计算图像特征&#xff09;。废话不多说&#xff0c;直接来&#xff0c;见下图。…

快速入门Java NIO(Not I/O)的网络通信框架--Netty

Netty 入门 了解netty前需要对nio有一定认识,该笔记基础来自bilinbili黑马,在此基础上自己学习的笔记,添加了一些自己的理解 了解java 非阻塞io编程 1. 概述 1.1 Netty 是什么&#xff1f; Netty is an asynchronous event-driven network application framework for rapid …

掌握这些测试开发技能,从容应对工作难题!

各位小伙伴, 大家好, 本期为大家分享一些测试开发工程师在企业中通过哪些测试开发技能解决难题。 一.如何定位缺陷 在企业中, 小伙伴们在发现bug后, 需要定位到具体产生bug的原因, 在这种情况下, 我们可以通过以下几种方案: 1.通过代理抓包来分析 常用的抓包工具有: Charles…

R语言【paleobioDB】——pbdb_subtaxa():统计指定类群下的子类群数量

Package paleobioDB version 0.7.0 paleobioDB 包在2020年已经停止更新&#xff0c;该包依赖PBDB v1 API。 可以选择在Index of /src/contrib/Archive/paleobioDB (r-project.org)下载安装包后&#xff0c;执行本地安装。 Usage pbdb_subtaxa (data, do.plot, col) Arguments…

Monorepo-uniapp 构建分享

Monorepo uniapp 构建灵感&#xff1a;刚好要做一个项目&#xff0c;于是想到升级一下之前自己写的一个vue3tspiniauno的模版框架&#xff0c;其实那个框架也不错&#xff1b;只是感觉还差点东西&#xff0c;我已经用那个小框架写了两三个项目&#xff1b;轻巧实用。为什么选…

CNN:Convolutional Neural Network(上)

目录 1 为什么使用 CNN 处理图像 2 CNN 的整体结构 2.1 Convolution 2.2 Colorful image 3 Convolution v.s. Fully Connected 4 Max Pooling 5 Flatten 6 CNN in Keras 原视频&#xff1a;李宏毅 2020&#xff1a;Convolutional Neural Network 1 为什么使用…