日撸 Java 三百行day36

news2025/1/11 5:04:24

文章目录

  • day36 领接表
    • 1. 领接表知识点
    • 2.结合上图去抽象一个邻接表结点的对象
    • 3.广度优先遍历
    • 4.深度优先遍历

#说明
闵老师的文章链接: 日撸 Java 三百行(总述)_minfanphd的博客-CSDN博客
自己也把手敲的代码放在了github上维护:https://github.com/fulisha-ok/sampledata

day36 领接表

1. 领接表知识点

领接表也是图的一种存储结构,之前的存储是领接矩阵。领接表是数组和链表的结合,其中有一个顶点数组和边表组成,如下图所示。对于稀疏图,如果用领接矩阵,有10个节点,则需要10*10的空间,但利用率很低,但是对于邻接表的存储可能需要的空间更少。
在这里插入图片描述

2.结合上图去抽象一个邻接表结点的对象

  • 对于顶点数组中,每个结点存的是结点的值,而在边表中的每个结点存储的是顶点数组的下标位置所以对结点的抽象数据就有一个column和一个next
 class AdjacencyNode {
        /**
         * The column index.
         */
        int column;
        /**
         * The next adjacent node.
         */
        AdjacencyNode next;

        /**
         *  The first constructor.
         * @param paraColumn
         */
        public AdjacencyNode(int paraColumn) {
            column = paraColumn;
            next = null;
        }
    }
  • 对于一个邻接表的构造,从代码中可以知道,对于headers数组的colum设置 为-1,并没有存放数据。在这个构造函数中,tempPreviousNode和tempNode两个变量让顶点数组和边表连接起来了
 public AdjacencyList(int[][] paraMatrix) {
        numNodes = paraMatrix.length;

        // Step 1. Initialize. The data in the headers are not meaningful.
        AdjacencyNode tempPreviousNode, tempNode;

        headers = new AdjacencyNode[numNodes];
        for (int i = 0; i < numNodes; i++) {
            headers[i] = new AdjacencyNode(-1);
            tempPreviousNode = headers[i];
            for (int j = 0; j < numNodes; j++) {
                if (paraMatrix[i][j] == 0) {
                    continue;
                }

                tempNode = new AdjacencyNode(j);
                tempPreviousNode.next = tempNode;
                tempPreviousNode = tempNode;
            }
        }
    }

一下数组在初始化后的存储结构,这个.打断点看headers数据结构

int[][] tempMatrix = { { 0, 1, 1, 0 }, { 1, 0, 0, 1 }, { 1, 0, 0, 1 }, { 0, 1, 1, 0 } };

在这里插入图片描述

在这里插入图片描述

3.广度优先遍历

  • 邻接表的广度优先也会借助队列实现(以索引2开始)
    访问头节点2,将2的边表结点(0,3)访问完并入队列,然后出队列0访问其边结点1,2(并判断是否已经被访问过)依次来访问所有结点
    在这里插入图片描述$$
  • 邻接矩阵
    访问结点2,并判断其他所有结点与2之间有相连(则横向看2与0,3相连,则把0,3入队列),1,2跳过;之后又0出队列,并判断其他所有结点与0之间有相连等,以这样的方式来进行广度遍历
    Δ 0 1 2 3 0 0 1 1 0 1 1 0 0 1 2 1 0 0 1 3 0 1 1 0 \begin{array}{c} % 总表格 \begin{array}{c|cccc} % 第二行 Delta 值数组 \Delta & 0 & 1 & 2 & 3 \\ \hline 0 & 0 & 1 & 1 & 0 \\ 1 & 1 & 0 & 0 & 1 \\ 2 & 1 & 0 & 0 & 1\\ 3 & 0 &1 & 1 & 0 \\ \end{array} % 第二行表格结束 \end{array} % 总表格结束 Δ012300110110012100130110
  • 从邻接表和邻接矩阵实现广度遍历的过程中,我们可以发现,邻接表在判断结点的相邻结点时更容易,只需要访问其边表结点即可,而邻接矩阵要遍历所有的结点,所以当数据量很大的时候,邻接表的效率会高点。所以从代码上来看,邻接矩阵和邻接表的到差不差,主要区别在于遍历结点方式上。领接矩阵是for循环了所有结点,而邻接矩阵是while当前访问头结点的边表结点即可。
 public String breadthFirstTraversal(int paraStartIndex) {
        CircleObjectQueue tempQueue = new CircleObjectQueue();
        String resultString = "";

        boolean[] tempVisitedArray = new boolean[numNodes];

        tempVisitedArray[paraStartIndex] = true;

        // Initialize the queue.
        // Visit before enqueue.
        tempVisitedArray[paraStartIndex] = true;
        resultString += paraStartIndex;
        tempQueue.enqueue(new Integer(paraStartIndex));

        // Now visit the rest of the graph.
        int tempIndex;
        Integer tempInteger = (Integer) tempQueue.dequeue();
        AdjacencyNode tempNode;
        while (tempInteger != null) {
            tempIndex = tempInteger.intValue();

            // Enqueue all its unvisited neighbors. The neighbors are linked
            // already.
            tempNode = headers[tempIndex].next;
            while (tempNode != null) {
                if (!tempVisitedArray[tempNode.column]) {
                    // Visit before enqueue.
                    tempVisitedArray[tempNode.column] = true;
                    resultString += tempNode.column;
                    tempQueue.enqueue(new Integer(tempNode.column));
                } // Of if
                tempNode = tempNode.next;
            } // Of for i

            // Take out one from the head.
            tempInteger = (Integer) tempQueue.dequeue();
        } // Of while

        return resultString;
    }

4.深度优先遍历

  • 邻接表的深度优先借助栈实现(以索引2开始)
    访问头节点2,将2的边表结点(0)访问完并入栈,然后接着访问头结点为0的边表结点1,访问完1再将1入栈,头节点为1的边表结点0,发现已经被访问过则跳过,访问3并将3入栈,然后访问3的边表结点都访问过就回溯。
    在这里插入图片描述

  • 邻接矩阵
    访问结点2,将2结点入栈,判断2结点以外的所有结点是否被访问过且是否与2结点相邻,发现0结点符合条件则跳出循环,将0结点入栈,接着又开始判断0结点的条件,以此类推。
    Δ 0 1 2 3 0 0 1 1 0 1 1 0 0 1 2 1 0 0 1 3 0 1 1 0 \begin{array}{c} % 总表格 \begin{array}{c|cccc} % 第二行 Delta 值数组 \Delta & 0 & 1 & 2 & 3 \\ \hline 0 & 0 & 1 & 1 & 0 \\ 1 & 1 & 0 & 0 & 1 \\ 2 & 1 & 0 & 0 & 1\\ 3 & 0 &1 & 1 & 0 \\ \end{array} % 第二行表格结束 \end{array} % 总表格结束 Δ012300110110012100130110

  • 从邻接表和邻接矩阵实现深度遍历的过程中,主要区别也是在访问相邻结点区别上。如下代码

 public String depthFirstTraversal(int paraStartIndex) {
        ObjectStack tempStack = new ObjectStack();
        String resultString = "";

        boolean[] tempVisitedArray = new boolean[numNodes];
        tempVisitedArray[paraStartIndex] = true;
        resultString += paraStartIndex;
        tempStack.push(new Integer(paraStartIndex));
        System.out.println("Push " + paraStartIndex);
        System.out.println("Visited " + resultString);

        int tempIndex = paraStartIndex;
        int tempNext;
        Integer tempInteger;
        AdjacencyNode tempNode;
        while (true) {
            tempNext = -1;
            // Find an unvisited neighbor and push
            tempNode = headers[tempIndex].next;
            while (tempNode != null) {
                if (!tempVisitedArray[tempNode.column]) {
                    // Visit before enqueue.
                    tempVisitedArray[tempNode.column] = true;
                    resultString += tempNode.column;
                    tempStack.push(new Integer(tempNode.column));
                    System.out.println("Push " + tempNode.column);
                    tempNext = tempNode.column;
                    break;
                } // Of if
                tempNode = tempNode.next;
            }

            if (tempNext == -1) {
                //there is no neighbor node, pop
                tempInteger = (Integer) tempStack.pop();
                System.out.println("Pop " + tempInteger);
                if (tempStack.isEmpty()) {
                    //No unvisited neighbor。Backtracking to the last one stored in the stack
                    break;
                } else {
                    tempInteger = (Integer) tempStack.pop();
                    tempIndex = tempInteger.intValue();
                    tempStack.push(tempInteger);
                }
            } else {
                tempIndex = tempNext;
            }
        }
        return resultString;
    }

##5.代码

package graph;

import datastructure.queue.CircleObjectQueue;
import datastructure.stack.ObjectStack;

/**
 * @author: fulisha
 * @date: 2023/4/24 11:34
 * @description:
 */
public class AdjacencyList {
    /**
     * An inner class for adjacent node.
     */
    class AdjacencyNode {
        /**
         * The column index.
         */
        int column;
        /**
         * The next adjacent node.
         */
        AdjacencyNode next;

        /**
         * The first constructor.
         *
         * @param paraColumn
         */
        public AdjacencyNode(int paraColumn) {
            column = paraColumn;
            next = null;
        }
    }

    int numNodes;
    AdjacencyNode[] headers;

    public AdjacencyList(int[][] paraMatrix) {
        numNodes = paraMatrix.length;

        // Step 1. Initialize. The data in the headers are not meaningful.
        AdjacencyNode tempPreviousNode, tempNode;

        headers = new AdjacencyNode[numNodes];
        for (int i = 0; i < numNodes; i++) {
            headers[i] = new AdjacencyNode(-1);
            tempPreviousNode = headers[i];
            for (int j = 0; j < numNodes; j++) {
                if (paraMatrix[i][j] == 0) {
                    continue;
                }

                tempNode = new AdjacencyNode(j);
                tempPreviousNode.next = tempNode;
                tempPreviousNode = tempNode;
            }
        }
    }

    @Override
    public String toString() {
        String resultString = "";
        AdjacencyNode tempNode;
        for (int i = 0; i < numNodes; i++) {
            tempNode = headers[i].next;

            while (tempNode != null) {
                resultString += " (" + i + ", " + tempNode.column + ")";
                tempNode = tempNode.next;
            } // Of while
            resultString += "\r\n";
        }
        return resultString;
    }


    boolean[] tempVisitedArray;
    String resultString = "";

    public String breadthFirstTraversal(int paraStartIndex) {
        CircleObjectQueue tempQueue = new CircleObjectQueue();
        String resultString = "";
        tempVisitedArray = new boolean[numNodes];

        tempVisitedArray[paraStartIndex] = true;

        // Initialize the queue.
        // Visit before enqueue.
        tempVisitedArray[paraStartIndex] = true;
        resultString += paraStartIndex;
        tempQueue.enqueue(new Integer(paraStartIndex));

        // Now visit the rest of the graph.
        int tempIndex;
        Integer tempInteger = (Integer) tempQueue.dequeue();
        AdjacencyNode tempNode;
        while (tempInteger != null) {
            tempIndex = tempInteger.intValue();

            // Enqueue all its unvisited neighbors. The neighbors are linked
            // already.
            tempNode = headers[tempIndex].next;
            while (tempNode != null) {
                if (!tempVisitedArray[tempNode.column]) {
                    // Visit before enqueue.
                    tempVisitedArray[tempNode.column] = true;
                    resultString += tempNode.column;
                    tempQueue.enqueue(new Integer(tempNode.column));
                } // Of if
                tempNode = tempNode.next;
            } // Of for i

            // Take out one from the head.
            tempInteger = (Integer) tempQueue.dequeue();
        } // Of while

        return resultString;
    }

    public String depthFirstTraversal(int paraStartIndex) {
        ObjectStack tempStack = new ObjectStack();
        resultString = "";
        tempVisitedArray = new boolean[numNodes];

        tempVisitedArray[paraStartIndex] = true;
        resultString += paraStartIndex;
        tempStack.push(new Integer(paraStartIndex));
        System.out.println("Push " + paraStartIndex);
        System.out.println("Visited " + resultString);

        int tempIndex = paraStartIndex;
        int tempNext;
        Integer tempInteger;
        AdjacencyNode tempNode;
        while (true) {
            tempNext = -1;
            // Find an unvisited neighbor and push
            tempNode = headers[tempIndex].next;
            while (tempNode != null) {
                if (!tempVisitedArray[tempNode.column]) {
                    // Visit before enqueue.
                    tempVisitedArray[tempNode.column] = true;
                    resultString += tempNode.column;
                    tempStack.push(new Integer(tempNode.column));
                    System.out.println("Push " + tempNode.column);
                    tempNext = tempNode.column;
                    break;
                } // Of if
                tempNode = tempNode.next;
            }

            if (tempNext == -1) {
                //there is no neighbor node, pop
                tempInteger = (Integer) tempStack.pop();
                System.out.println("Pop " + tempInteger);
                if (tempStack.isEmpty()) {
                    //No unvisited neighbor。Backtracking to the last one stored in the stack
                    break;
                } else {
                    tempInteger = (Integer) tempStack.pop();
                    tempIndex = tempInteger.intValue();
                    tempStack.push(tempInteger);
                }
            } else {
                tempIndex = tempNext;
            }
        }
        return resultString;
    }
    public boolean breadthTraversal(int paraStartIndex) {
        tempVisitedArray = new boolean[numNodes];
        resultString = "";
        breadthFirstTraversal(paraStartIndex);

        for (int i = 0; i < numNodes; i++){
            if (!tempVisitedArray[i]){
                breadthFirstTraversal(i);
                return false;
            }
        }
        return true;
    }

    public boolean depthTraversal(int paraStartIndex){
        tempVisitedArray = new boolean[numNodes];
        resultString = "";
        depthFirstTraversal(paraStartIndex);

        for (int i = 0; i < numNodes; i++){
            if (!tempVisitedArray[i]){
                depthFirstTraversal(i);
                return false;
            }
        }
        return true;
    }





    public static void breadthFirstTraversalTest() {
        // Test an undirected graph.
        int[][] tempMatrix = { { 0, 1, 1, 0 }, { 1, 0, 0, 1 }, { 1, 0, 0, 0}, { 0, 1, 0, 0} };
        // int[][] tempMatrix = { { 0, 1, 1, 0 , 0}, { 1, 0, 0, 1, 0 }, { 1, 0, 0, 1, 0}, { 0, 1, 1, 0, 0}, { 0, 0, 0, 0, 0} };
       // int[][] tempMatrix = { { 0, 1, 1, 0 , 0, 0, 0}, { 1, 0, 0, 1, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0}, { 0, 1, 1, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 1, 1}, { 0, 0, 0, 0, 1, 0, 0}, { 0, 0, 0, 0, 0, 0, 0} };
        Graph tempGraph = new Graph(tempMatrix);
        System.out.println(tempGraph);
        AdjacencyList tempAdjList = new AdjacencyList(tempMatrix);

        String tempSequence = "";
        try {
           // tempSequence = tempAdjList.breadthFirstTraversal(2);
            tempGraph.breadthTraversal(0);
        } catch (Exception ee) {
            System.out.println(ee);
        } // Of try.

        System.out.println("The breadth first order of visit: " + tempGraph.resultString);
    }

    public static void depthFirstTraversalTest() {
        // Test an undirected graph.
        int[][] tempMatrix = { { 0, 1, 1, 0 }, { 1, 0, 0, 1 }, { 1, 0, 0, 0}, { 0, 1, 0, 0} };
         //int[][] tempMatrix = { { 0, 1, 1, 0 , 0}, { 1, 0, 0, 1, 0 }, { 1, 0, 0, 1, 0}, { 0, 1, 1, 0, 0}, { 0, 0, 0, 0, 0} };
        //int[][] tempMatrix = { { 0, 1, 1, 0 , 0, 0, 0}, { 1, 0, 0, 1, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0}, { 0, 1, 1, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 1, 1}, { 0, 0, 0, 0, 1, 0, 0}, { 0, 0, 0, 0, 0, 0, 0} };
        Graph tempGraph = new Graph(tempMatrix);
        System.out.println(tempGraph);
        AdjacencyList tempAdjList = new AdjacencyList(tempMatrix);

        String tempSequence = "";
        try {
            tempGraph.depthTraversal(0);
           // tempSequence = tempAdjList.depthFirstTraversal(2);
        } catch (Exception ee) {
            System.out.println(ee);
        } // Of try.

        System.out.println("The depth first order of visit: " + tempGraph.resultString);
    }


    public static void main(String args[]) {
        int[][] tempMatrix = { { 0, 1, 0 }, { 1, 0, 1 }, { 0, 1, 0 } };
        AdjacencyList tempTable = new AdjacencyList(tempMatrix);
        System.out.println("The data are:\r\n" + tempTable);

        breadthFirstTraversalTest();

        depthFirstTraversalTest();
    }

}

  • 单元测试1
    在这里插入图片描述

在这里插入图片描述

  • 单元测试2
    在这里插入图片描述

在这里插入图片描述

  • 单元测试3
    在这里插入图片描述

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3+Three.js+antvG2实战项目 智慧城市(三)

前言 在网上找了很久都没有找到使用Three.js开发智慧城市的免费文章或者免费视频,自己花了一点时间做了一个纯前端的智慧城市项目。 技术栈都是最新的:vue3vitetypeScriptThreeantv G2 源码分享 源码 模型,天空图盒子链接分享(不想下载源码可以只用下这个)提取码1234 20230424_…

【iOS】—— KVC再学习

KVC 文章目录 KVCKVC常用的四种方法 key和keyPath的区别用法&#xff1a; 批量存值操作批量赋值操作字典模型相互转化KVC的其他方法 KVC原理探索setValue:forKey: 的原理&#xff08;KVC赋值原理&#xff09;valueForKey:的原理&#xff08;KVC取值原理&#xff09; 注意事项 K…

C++数据结构:手撕AVL树

目录 一. 什么是AVL树 二. AVL树的节点定义 三. AVL树的插入操作 3.1 寻找插入位置 3.2 更新平衡因子 3.3 AVL树的旋转调整 3.4 AVL树插入操作的整体实现 四. AVL树的检验 附录&#xff1a;AVL树的实现完整代码 AVL树定义代码 -- AVLTree.h AVL树检验代码 -- test.…

你了解PostProcessor机制吗?

Spring框架对于后置处理器的最佳实践 PostProcessor译为后置处理器&#xff0c;大多数开发人员都使用过springboot对后置处理器的实例级别实践&#xff0c;也就是BeanPostProcessor接口。其实spring还提供了两种容器级别的实践&#xff1a;BeanDefinitionRegistryPostProcesso…

今天试了试chatgpt

今天试了试chatgpt&#xff0c;真是服了 arcade&#xff1f; Arcade是一个Python游戏开发库&#xff0c;它提供了一系列的工具和函数&#xff0c;可以帮助开发者快速地创建2D游戏。以下是Arcade的一些特点&#xff1a; 简单易用&#xff1a;Arcade提供了简单易用的API&#x…

egg3.0连接egg-mongoose插入一条数据、插入多条数据

插入一条数据 app/router.js use strict;/*** param {Egg.Application} app - egg application*/ module.exports app > {const { router, controller } app;router.get(/, controller.home.index);router.get(/role, controller.role.index);router.post(/role/add, co…

【ChatGPT】如何用十分钟部署一个属于自己的chatgpt网站

&#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是Zeeland&#xff0c;全栈领域优质创作者。&#x1f4dd; CSDN主页&#xff1a;Zeeland&#x1f525;&#x1f4e3; 我的博客&#xff1a;Zeeland&#x1f4da; Github主页: Undertone0809 (Zeeland) (github.com)&…

【两个月算法速成】day03-链表

目录 203. 移除链表元素 题目链接 思路 代码 206. 反转链表 题目链接 思路 代码 总结 203. 移除链表元素 题目链接 力扣 思路 如下图所示就是移除链表的过程 但是值得注意的是&#xff0c;移除头节点和其他位置的节点是不一样的&#xff0c;以为头结点前面没有节点。…

每日学术速递4.24

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Collaborative Diffusion for Multi-Modal Face Generation and Editing(CVPR 2023) 标题&#xff1a;多模态人脸生成和编辑的协同扩散 作者&#xff1a;Ziqi Huang, Kelvin C.K. …

Vue3进阶使用详解(node.js、Vue3路由基础项目、axios的使用详细(实现数据分页---前后端分离)、axios加载失败)

Vue3进阶使用详解(node.js、Vue3路由基础项目、axios的使用详细(实现数据分页—前后端分离)、axios加载失败) Vue cli CLI是Commond-Line Interface&#xff0c;翻译为命令界面&#xff0c;又称脚手架。VueCLI是一个官方发布vue.js项目脚手架。使用VueCLI可以快速搭建vue开发…

【IAR工程】STM8S基于ST标准库读取DHT11数据

【IAR工程】STM8S基于ST标准库读取DHT11数据 ✨申明&#xff1a;本文章仅发表在CSDN网站&#xff0c;任何其他网站&#xff0c;未注明来源&#xff0c;见此内容均为盗链和爬取&#xff0c;请多多尊重和支持原创!&#x1f341;对于文中所提供的相关资源链接将作不定期更换。&…

HTTP协议 GET和POST区别 请求响应 Fiddler postman ajax

&#x1f496; 欢迎来阅读子豪的博客&#xff08;JavaEE篇 &#x1f934;&#xff09; &#x1f449; 有宝贵的意见或建议可以在留言区留言 &#x1f4bb; 欢迎 素质三连 点赞 关注 收藏 &#x1f9d1;‍&#x1f680;码云仓库&#xff1a;补集王子的代码仓库 不要偷走我小火…

Mac下nvm安装使用

​欢迎光临我的博客查看最新文章: https://river106.cn 1、简介 nvm 是 Mac 下的 node.js 管理工具。可以通过 nvm 安装和切换不同版本的 node.js。 官网&#xff1a;https://nvm.uihtm.com/ github&#xff1a;https://github.com/nvm-sh/nvm 2、安装 curl -o- https://raw…

移动端适配rem方案

做移动端的适配我们就是要考虑&#xff0c;对于不同大小的手机屏幕&#xff0c;怎么动态改变页面布局中所有盒子的宽度高度、字体大小等。 这个问题我们可以使用相对单位rem。 那么什么是 rem&#xff1f; rem&#xff08;font size of the root element&#xff09;是指相对…

Linux-中断和时间管理(上)

目录 中断的进入过程 中断的进入过程 为方便实验&#xff0c;本章以配套的目标板 FS4412为例来介绍 Linux 的中断子系统&#xff0c;并且编写相应的中断处理程序。FS4412 上的处理器是 SAMSUNG公司的 Exynos4412&#xff0c;该处理器使用的是4核的 Cortex-A9&#xff0c;&…

c++Lambda匿名函数

cLambda匿名函数 &#xff08;1&#xff09; 定义a. [外部变量方位方式说明符]b. (参数)c. mutabled.noexcept/throw()e.->返回值类型f.函数体 2&#xff09;c11中的拉姆达表达式中的&#xff08;&#xff09;可以省略吗 所谓匿名函数&#xff0c;简单地理解就是没有名称的函…

《C++ Primer Plus》(第6版)第17章编程练习

《C Primer Plus》&#xff08;第6版&#xff09;第17章编程练习 《C Primer Plus》&#xff08;第6版&#xff09;第17章编程练习1. 计算输入流中第一个\$之前的字符数目2. 将键盘输入&#xff08;直到模拟的文件尾&#xff09;复制到通过命令行指定的文件中3. 将一个文件复制…

完全免费的基于区块链和 IPFS 的去中心化博客平台

一、前言 xLog是一个基于Crossbell区块链的博客解决方案&#xff0c;专注于Web3数据由用户掌控。Crossbell是一个基于Web3技术的去中心化博客平台&#xff0c;用户可以在该平台上发布文章并进行交流和创作。社区提供多种交流平台和有奖创作活动。 xLog是基于 Crossbell 区块链…

【AI回复】“我问它,你对五一调休怎么看”

前言 马上就要到五一啦&#xff0c;放假打算去哪里玩呢&#xff1f; “我肯定是宅在家里写博客啊” 最近五一调休在某博上引起大家的共鸣&#xff0c;看了评论那叫一个惨不忍睹哇。 因为我比较对AI感兴趣&#xff0c;所以想看看它是怎么看待调休的。 首先&#xff0c;在百度…

【UE】简易的水材质

引擎版本&#xff1a;4.26 效果 步骤 1. 创建一个材质&#xff0c;命名为“M_Water” 2. 打开“M_Water”&#xff0c;将混合模式设为半透明&#xff0c; 光照模式设为表面半透明体积&#xff0c;在这种模式下我们可以使用金属度、粗糙度等接口 3. 创建一个4维常量节点&…