最常见的20个SQL优化类问题

1,为什么建议在大表(>1.000.000)行上创建索引? 在大表(超过1,000,000行)上创建索引的主要理由是为了提高查询性能和减少查询时间。以下是一些具体的原因: 加快数据检索:在大表上进行查询时,如果没有索引,数据库需要进行全表扫描来找到匹配的数据行。这种全表扫描需要遍历整个表,对于大表而言,会消耗大量的时间和资源。而通过在适当的列上创建索引,数据库可以快速定位到匹配的数据行,从而加快数据检索过程。减少磁盘IO:大表通常会占用大量的磁盘空间,读取整个表的数据需要大量的磁盘IO操作。通过创建索引,数据库可以减少需要读取的磁盘数据量,只需访问索引数据即可定位到所需的数据行,从而减少磁盘IO操作,提高查询性能。优化查询计划:数据库查询优化器在生成查询执行计划时会考虑索引的存在。通过创建适当的索引,可以帮助优化器选择更有效的执行计划,以最小化查询的成本和执行时间。索引可以提供更多的统计信息,帮助优化器做出更准确的成本估算和选择最佳的执行路径。支持快速排序和连接操作:在大表上进行排序和连接操作可能会非常耗时,特别是在没有索引的情况下。通过在排序和连接的列上创建索引,可以大大减少排序和连接操作的时间,提高查询性能。 2,为什么建议使用EXIST ()而不是COUNT ()来查找表中的元素? 在MySQL中,使用EXISTS()而不是COUNT()来查找表中的元素有几个原因: 查询效率:在查找表中是否存在符合某个条件的数据时,EXISTS()函数通常比COUNT()更高效。EXISTS()函数在找到第一个匹配项后就会停止搜索,而COUNT()函数需要遍历整个表来计算满足条件的行数。因此,当只关心是否存在满足条件的数据时,使用EXISTS()函数可以提高查询效率。内存消耗:COUNT()函数会将满足条件的所有行加载到内存中,以便计算行数。对于大型表或满足条件的行数较多的情况下,COUNT()函数可能会占用大量的内存资源。而EXISTS()函数只需找到第一个匹配项即可,不需要加载和计算所有行,因此可以减少内存消耗。语义明确:使用EXISTS()函数可以更清晰地表达查询的意图。当使用EXISTS()函数时,查询语句的目的是检查是否存在满足条件的数据,而不关心具体的行数。这可以使查询语句更易于理解和维护。 3,为什么SELECT字段而不是使用SELECT * 在编写SQL查询语句时,建议明确列出需要查询的字段,而不是使用SELECT *。以下是一些原因: 减少数据传输量:使用SELECT *会返回表中的所有列,包括可能不需要的列。如果表包含大量的列或者某些列具有较大的数据量,使用SELECT *会导致不必要的数据传输,增加网络开销和查询的响应时间。明确列出需要的字段可以减少传输的数据量,提高查询性能。避免不必要的列冲突:如果查询涉及多个表,这些表可能具有相同的列名。使用SELECT *可能导致列名冲突,使查询结果不明确或产生错误。通过明确列出需要的字段,可以避免这种潜在的问题,并确保查询结果的准确性。提供更好的查询意图和可读性:明确列出需要的字段可以使查询语句更具可读性和表达意图。使用SELECT *可能会隐藏查询的真实意图,使代码更难理解和维护。通过明确选择需要的字段,可以更清晰地表达查询的目的和需求,使代码更易于理解和维护。优化查询性能:明确列出需要的字段可以帮助查询优化器生成更有效的查询计划。查询优化器可以更准确地评估查询的成本,并选择更适合的索引和执行策略。这可能导致更快的查询速度和更好的性能。 在某些情况下使用SELECT *可能是合适的,例如在查询所有列的简单查询或进行快速的数据探索时,但在大多数情况下,明确列出需要的字段是更好的做法,以提高查询性能、可读性和代码的可维护性。 4,为什么建议避免在 WHERE 子句中使用子查询 在WHERE子句中使用子查询是可能的,但一般建议避免过度或复杂地使用子查询,特别是在大型数据集上执行复杂查询时。以下是一些原因: 性能问题:子查询可能会导致性能问题,尤其是在处理大型数据集时。子查询通常需要执行多个查询操作,并且每个子查询都可能涉及表的扫描或连接操作。这会增加数据库的负载和查询的响应时间。相比之下,使用JOIN等其他技术可以更有效地处理复杂查询。可读性和维护性:使用子查询可能会使查询语句变得复杂,难以理解和维护。子查询嵌套在主查询中,使得整个查询的逻辑和意图不太明确。这可能导致代码的可读性下降,并给后续的维护工作带来困难。数据一致性问题:如果子查询依赖于外部查询的结果,且外部查询在执行期间发生了更改,可能导致子查询的结果不准确或不一致。这是因为子查询的执行是在外部查询之后发生的。使用其他连接技术,如JOIN,可以更好地处理数据一致性问题。缺乏优化机会:对于子查询,数据库优化器的优化能力可能会受到限制。优化器难以对子查询进行准确的成本估算和优化选择,可能导致查询性能不佳。相比之下,使用其他连接技术,优化器可以更好地评估和优化查询计划。 简单的子查询或在小型数据集上执行的查询一般来说子查询可以使用,但在复杂查询和大型数据集的情况下,使用其他连接技术,如JOIN,可以更好地处理查询需求,提高性能和可维护性。之所以不推荐是因为数据集的发展存在不确定性,当前小数据集使用了子查询未来数据发展后就需要优化代码调整,导致了不必要的优化负担。 5,为什么尽可能避免 SELECT DISTINCT? SELECT DISTINCT用于返回结果集中唯一的行,即去除重复的行。尽管SELECT DISTINCT在某些情况下是有用的,但也有一些原因建议尽可能避免使用它: 性能开销:SELECT DISTINCT可能会导致性能开销较大。当查询结果集较大时,数据库需要对所有返回的行进行排序和比较,以确定唯一行。这可能需要大量的CPU和内存资源,并且会增加查询的执行时间。数据库优化限制:SELECT DISTINCT对数据库优化器的能力有一定限制。优化器可能无法有效利用索引或其他优化策略来处理SELECT DISTINCT查询。这可能导致查询执行计划的选择不佳,从而降低查询性能。不必要的去重:有时候,使用SELECT DISTINCT是为了去除查询结果中的重复行。然而,有时这种去重是不必要的,因为查询本身已经保证了结果集中的唯一性。在这种情况下,使用SELECT DISTINCT可能是一种浪费资源的做法。可读性和维护性:使用SELECT DISTINCT可能会使查询语句更加复杂,不易理解和维护。SELECT DISTINCT隐藏了查询的真实意图,使代码更难以理解。在许多情况下,可以通过正确设计查询条件和使用其他技术(例如合适的JOIN语句)来避免使用SELECT DISTINCT。 SELECT DISTINCT在某些情况下是必需的,但在能够通过其他方式满足查询需求时,尽量避免使用它可以提高查询性能、可读性和可维护性。如果需要使用SELECT DISTINCT,请确保在性能和资源消耗方面进行评估,并确保它是实际需要的解决方案。 6,为什么推荐使用 WHERE 子句代替 HAVING 推荐使用WHERE子句而不是HAVING子句有几个原因: 过滤效率:WHERE子句在查询之前进行过滤,可以排除不满足条件的行,减少需要处理的数据量。这样可以提高查询的效率,尤其是在大型数据集上或涉及复杂条件的查询中。相比之下,HAVING子句是在数据已经被检索和分组之后进行过滤,可能会造成不必要的计算和处理。语义明确:WHERE子句用于对行进行筛选,根据给定的条件来选择满足条件的行。这更符合常规直觉,易于理解和维护。而HAVING子句用于对聚合结果进行筛选,即对分组后的数据进行条件过滤。使用WHERE子句可以更清晰地表达查询的意图,使代码更易于理解。适用范围:WHERE子句可以在查询中的任何位置使用,而HAVING子句只能在GROUP BY子句之后使用。因此,使用WHERE子句可以更自由地进行条件筛选,而不受限于分组操作。 当需要基于聚合结果进行条件过滤时,HAVING子句是唯一可行的选择。例如,当查询需要根据聚合函数(如SUM、AVG)计算结果后进行过滤时,使用HAVING子句才是正确的做法。 7,使用 INNER JOIN 创建连接(而不是 WHERE) 推荐使用INNER JOIN来创建连接,而不是使用WHERE子句进行连接,有以下几个理由: 显式表达连接关系:使用INNER JOIN可以明确地指定要连接的表以及连接条件,使查询语句更具可读性和可维护性。通过在查询中直接指定连接条件,可以清晰地表达表之间的关系,减少了代码的歧义性。语义清晰:INNER JOIN语法更符合直觉,并且更容易理解和解释。通过在查询中使用INNER JOIN,可以直接将连接操作与其他查询条件分离开来,使查询语句的结构更清晰,易于理解和修改。查询性能优化:数据库优化器在使用INNER JOIN时通常具有更好的优化能力。优化器可以根据连接条件、索引和表的统计信息来生成更优化的查询计划,从而提高查询性能。相比之下,使用WHERE子句进行连接可能会限制优化器的优化能力,导致查询性能下降。处理多个连接条件:当需要处理多个连接条件时,使用INNER JOIN可以更方便地组合这些条件。通过在JOIN子句中指定多个连接条件,可以更清晰地定义表之间的关系,并避免WHERE子句中出现复杂的逻辑运算符和括号。 使用INNER JOIN并不意味着在所有情况下都优于使用WHERE子句进行连接。在某些情况下,使用WHERE子句进行连接可能更加合适,例如在连接条件是动态生成的或者需要灵活性更高的情况下。根据具体的查询需求和性能要求,选择合适的连接方式是重要的。 8,为什么推荐使用LIMIT对查询结果进行采样? 推荐使用LIMIT对查询结果进行采样的原因有以下几点: 减少数据传输量:当查询结果集非常大时,一次性返回全部结果可能会导致网络传输延迟和资源消耗。通过使用LIMIT,可以限制返回的行数,减少数据传输量,提高查询性能。快速获取部分结果:有时候,我们只对查询结果的一部分感兴趣,而不需要所有的数据。使用LIMIT可以快速获取部分结果,满足我们的需求。这在交互式应用程序中尤为常见,例如分页显示查询结果或实时监控某个数据集。节约资源:在数据库服务器上执行查询时,返回大量结果会占用内存和CPU资源。通过使用LIMIT,可以限制结果集的大小,减少对服务器资源的占用,从而保持系统的健康运行。 举例来说明,假设有一个名为"

c#编写控制LED灯的代码

由于NanoFramework是一个开源项目,具体的示例代码可能会随着项目的更新而发生变化。不过,我可以为你提供一个简单的NanoFramework示例,用于演示如何在基于NanoFramework的设备上控制一个LED灯的亮灭。 首先,确保你已经安装了NanoFramework的开发环境,包括Visual Studio扩展和所需的NuGet包。 接下来,创建一个新的NanoFramework项目。在Visual Studio中,选择“创建新项目”,然后搜索并选择“NanoFramework”项目模板。填写项目名称和位置,然后点击“创建”。 一旦项目创建完成,你将看到一个默认的Program.cs文件。在这个文件中,你可以编写控制LED灯的代码。下面是一个简单的示例: csharpusing System; using System.Threading; using NanoFramework.Hardware.Gpio; namespace NanoFrameworkLedExample { public class Program { private static GpioPin ledPin; public static void Main() { // 初始化GPIO控制器 var gpio = new GpioController(); // 打开LED引脚,假设LED连接在GPIO 02上 ledPin = gpio.OpenPin(2); ledPin.SetDriveMode(GpioPinDriveMode.Output); // 无限循环,控制LED灯的亮灭 while (true) { // 打开LED灯 ledPin.Write(GpioPinValue.High); // 等待一秒 Thread.Sleep(1000); // 关闭LED灯 ledPin.Write(GpioPinValue.Low); // 再等待一秒 Thread.Sleep(1000); } } } 在这个示例中,我们首先创建了一个GpioPin对象来表示LED灯连接的引脚。然后,我们使用GpioController的OpenPin方法来打开该引脚,并将其设置为输出模式。 接下来,我们使用一个无限循环来交替设置LED引脚的高低电平,从而控制LED灯的亮灭。每次状态改变后,我们使用Thread.Sleep方法来暂停一秒,以便观察LED灯的变化。 请注意,这个示例假设你的LED灯连接在GPIO 02上。根据你的硬件配置,你可能需要修改引脚编号。此外,确保你的设备支持NanoFramework,并且已经正确连接了LED灯和其他必要的硬件。

springboot实现密码过期,以及存储5次密码,第六次密码不能与前五次相同

增加是否启用密码过期配置 application.yml #密码有效期开关 passwordExpire: true #密码剩余天数提醒修改密码 passwordExpireTip: '#{3*24*60*60}' 1.已存在用户,第一次登录时判断是否存在redis密码过期设置和存储密码list,不存在,则生成redis信息,不存在,跳过。 代码示例: @Value(value = "${hhxxweb.passwordExpire}") private boolean passwordExpire; @PostMapping("/login") @ResponseBody public AjaxResult ajaxLogin(HttpServletRequest request,String username, String password, Boolean rememberMe) { try { String id = request.getSession().getId(); byte[] aesKey = StringUtils.hexToByteArray(RedisTool.get(String.format(Constants.LOGIN_AES_KEY, id), String.class)); if (ArrayUtil.isEmpty(aesKey)){ return error("登录超时,请刷新页面重试"); } username = Md5Utils.decryptAESCtr(StringUtils.hexToByteArray(username), aesKey); password = Md5Utils.decryptAESCtr(StringUtils.hexToByteArray(password), aesKey); if(passwordExpire) { if(!"zlxt_admin".equals(username)) { passwordExpire(username, password); String redisPassword = redisCache.getCacheObject("password:expire:" + username); if(StringUtils.isEmpty(redisPassword)) { String msg = "

基于自然语言处理的情感分析系统

案例:基于自然语言处理的情感分析系统 案例背景: 随着社交媒体和在线评论的普及,人们对于各类产品、服务、事件的意见和情感表达数量庞大。为了更好地了解用户的情感倾向,许多公司和研究机构开始探索利用自然语言处理技术来进行情感分析。情感分析系统能够自动识别和分析文本中的情感表达,帮助企业了解用户对其产品和服务的评价,从而做出更好的决策。 案例描述: 某企业拥有大量用户评论数据,希望利用自然语言处理技术开发一套情感分析系统,用于自动识别用户对其产品和服务的情感表达,从而了解用户的满意度,并及时作出调整。 实施步骤: 数据收集与预处理:从不同渠道(如社交媒体、在线评论平台)收集用户评论数据,并进行预处理,包括去除噪声字符、标记化、拼写纠错等。 情感词典构建:构建一个情感词典,其中包含积极情感词和消极情感词。可以利用已有的情感词库,也可以通过人工标注的方式构建。 特征提取:从文本中提取有助于情感分析的特征,如词袋模型、n-gram特征、词性标注、情感强度等。 模型训练与评估:使用已标注的数据集训练情感分类模型,如朴素贝叶斯、支持向量机、深度学习等。使用交叉验证等方法评估模型的性能。 情感分析系统开发:基于训练好的模型,开发一个情感分析系统,能够接收用户输入的文本,并输出情感极性(积极、消极)和情感强度的预测结果。 系统部署与优化:将开发好的情感分析系统部署到线上环境,并进行实时监测和优化,以提高系统的准确性和性能。 结果分析与应用:分析系统输出的情感分析结果,帮助企业了解用户的情感倾向,从而作出相应的决策和改进。 该情感分析系统可以广泛应用于企业的产品研发、市场营销、品牌管理等领域,帮助企业更好地了解用户需求和反馈,并及时做出调整和改进。

【WEEK1】【 DAY1】 MVC related history and concepts【English Version】

2024.2.26 Monday Contents 1. What is MVC2. The Model1 Era3. The Model2 Era4. Responsibility Analysis 1. What is MVC MVC stands for Model, View, and Controller, which is a software design paradigm.It is a method for organizing code by separating business logic, data, and presentation. The main purpose of MVC is to reduce the bidirectional coupling between views and business logic.MVC is not a design pattern, but an architectural pattern.

【WEEK1】【 DAY1】 MVC相关历史和概念【中文版】

2024.2.26 Monday 目录 1. 什么是MVC2. Model1时代3. Model2时代4. 职责分析 1. 什么是MVC MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。是将业务逻辑、数据、显示分离的方法来组织代码。 MVC主要作用是降低了视图与业务逻辑间的双向偶合。MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。 Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。最典型的MVC就是JSP + servlet + javabean的模式。 2. Model1时代 在web早期的开发中,通常采用的都是Model1Model1中,主要分为两层,视图层和模型层Model1优点:架构简单,比较适合小型项目开发Model1缺点:JSP职责不单一,职责过重,不便于维护 3. Model2时代 Model2把一个项目分成三部分,包括视图、控制、模型。 用户发请求Servlet接收请求数据,并调用对应的业务逻辑方法业务处理完毕,返回更新后的数据给servletservlet转向到JSP,由JSP来渲染页面响应给前端更新后的页面 4. 职责分析 Controller:控制器 取得表单数据调用业务逻辑转向指定的页面 Model:模型 业务逻辑保存数据的状态 View:视图 显示页面 Model2的优点:Model2这样不仅提高的代码的复用率与项目的扩展性,且大大降低了项目的维护成本。Model 1模式的实现比较简单,适用于快速开发小规模项目,Model1中JSP页面身兼View和Controller两种角色,将控制逻辑和表现逻辑混杂在一起,从而导致代码的重用性非常低,增加了应用的扩展性和维护的难度。Model2消除了Model1的缺点。

数据结构——栈和队列的表示与实现详解

目录 1.栈的定义与特点 2.队列的定义与特点 3.案例引入 4.栈的表示和操作的实现 1.顺序栈的表示 代码示例: 2.顺序栈的初始化 代码示例: 3.判断栈是否为空 代码示例: 4.求顺序栈长度 代码示例: 5.清空顺序栈 代码示例: 6.销毁顺序栈 代码示例: 7.顺序栈的入栈 代码示例: 8.顺序栈的出栈 代码示例: 5.链栈的表示和实现 代码示例: 1.链栈的初始化 代码示例: 2.判断链栈是否为空 代码示例: 3.链栈的入栈 代码示例: 4.链栈的出栈 代码示例: 5.取栈顶元素 代码示例: 6.栈与递归 1.递归问题的求法 2.递归的定义 3.递归的优缺点 7.队列的表示和操作 1.队列的抽象数据类型定义 2.队列的顺序表示和实现 代码示例: 3.解决假上溢的办法——循环队列 4.循环队列的类型定义 代码示例: 5.队列的初始化 代码示例: 6.求队列长度 代码示例: 7循环队列入队 代码示例: 8.循环队列出队 代码示例: 9.取队头元素 代码示例: 8.链队列 1.链队的类型定义 代码示例: 2.链队初始化 代码示例: 3.销毁链队列 代码示例: 4.将元素e入队 代码示例: 5.链队列出队 代码示例: 6.求链队列的队头元素 代码示例: 9.总的代码 1.栈的定义与特点 2.

搭建vue项目

1、下载vscode开发工具 2、下载node.js(win7建议下载12.0.0) 连接node.js官网http:// https://v2.cn.vuejs.org/3、基于Vue2的Element官网为: 链接: Element - The world's most popular Vue UI frameworkElement,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库https://element.eleme.io/#/zh-CN/component/installation 4、安装Vue脚手架,终端输入npm install -g @vue/cli,回车。 npm install -g @vue/cli 1、出现问题,解决 npm install -g @vue/cli 源文本中存在无法识别的标记。 所在位置 行:1 字符: 16 这里使用@符号时,要加''才行 npm install -g '@vue/cli ’ 如果还不行 将vscode右击----属性---兼容性---管理员运行 解决:无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\vue.ps1,因为在此系统中禁止执行脚本 cmd-输入powerShell弹出黑窗口 输入 set-ExecutionPolicy RemoteSigned 回车 输入 y

C++笔记:从零开始一步步手撕红黑树

文章目录 红黑树概念红黑树的性质红黑树 VS AVL树红黑树的结点与树的描述——定义类红黑树的插入操作步骤一:按照二叉搜索树的规则插入新结点步骤二:检测新节点插入后,红黑树的性质是否造到破坏情况一:uncle存在且为红情况二:uncle不存在或者uncle存在且为黑 验证一棵红黑树是否符合规则 红黑树概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色 ,可以是 Red 或 Black 。通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。 红黑树的性质 红黑树主要靠以下几条性质或者说规则达到高度近似平衡: 结点的颜色不是 黑色 就是 红色。根结点的颜色是 黑色。任意一条路径中不存在连续的红色结点。每条路径上的黑色结点数量相同。规定空结点才是叶子结点,叶子结点都是黑色的(主要作用:数路径)。 为什么满足以上几条规则,红黑树就能保证:最长路径的有效结点个数不超过最短路径结点个数的 2 倍,接下来举个例子证明一下: 红黑树 VS AVL树 平衡条件的严格性: AVL 树要求达到的是一种左右子树高度差的绝对值不超过 1 的绝对平衡; 红黑树要求达到的是一种最长路径上的结点数不超过最短路径上的结点数的 2 倍的近似平衡。 查找的效率分析: 假设红黑树和 AVL 树都具有 N N N 个结点: 对于AVL树:高度最多达到 l o g 2 ( N + 1 ) log_2(N+1) log2​(N+1),最坏的情况下的查找次数为 2 log ⁡ 2 ( N + 1 ) 2\log_2(N+1) 2log2​(N+1); 对于红黑树:高度最多达到 2 log ⁡ 2 ( N + 1 ) 2\log_2(N+1) 2log2​(N+1),最坏的情况下的查找次数为 2 log ⁡ 2 ( N + 1 ) 2\log_2(N+1) 2log2​(N+1);

惠州学院第二届大学生程序设计竞赛c++题解

惠州学院第二届大学生程序设计竞赛c++题解 题目总览7-1 关于闭区间的最值问题7-2 大厂必备技能!!!7-3 这可能是道签到题7-4 Nomi的计算器7-5 篮球二叉树7-6 回文文回7-7 求和游戏7-8 得分王7-9 玛恩纳7-10 涂矩阵 题目总览 按难度等级排序 题目难度知识点7-1 关于闭区间的最值问题签到二分答案 / 数学7-4 Nomi的计算器简单栈+模拟7-9 玛恩纳简单模拟7-10 涂矩阵简单前缀和+差分7-7 求和游戏中等贪心7-2 大厂必备技能!!!中等最短路径7-8 得分王中等深搜+广搜 / 全排列+拓扑7-5 篮球二叉树稍难思维+构造7-3 这可能是道签到题稍难欧拉函数+矩阵+快速幂+等比数列7-6 回文文回难线段树+字符串哈希 7-1 关于闭区间的最值问题 时间限制: 1.0s 内存限制:256.0MB 【问题描述】 给定 T 组测试样例 每组样例给定整数 n,x,请输出区间 [1, n] 中能被 x 整除的最大整数。 【输入格式】 第一行输入一个整数T,代表一共有T组测试样例。(1 ≤ T ≤ 1000) 接下来 T 行,每行两个整数 n, x。(1 ≤ x ≤ n ≤ 109 ) 【输出格式】 对每一组输入,在一行中输出答案值。 【样例输入】 5 10 6 6 6 4 2 9 1 7 5 【样例输出】

java 数据结构 二叉树

目录 树 树的概念 树的表示形式 二叉树 两种特殊的二叉树 二叉树的性质 二叉树的存储 二叉树的基本操作 二叉树的遍历 二叉树的基本操作 二叉树oj题 树 树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫 做树是因为它看 起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点: 有一个特殊的结点,称为根结点,根结点没有前驱结点 除根结点外,其余结点被分成M(M > 0)个互不相交的集合T1、T2、......、Tm,其中每一个集合Ti (1 <= i <=m) 又是一棵与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继 树是递归定义的 注意:树形结构中,子树之间不能有交集,否则就不是树形结构 一棵树是由若干个不相交的子树组成的 除了根结点之外,每个结点有且只有一个父结点 一棵N个结点的树有N-1条边 树的概念 结点的度:一个结点含有子树的个数称为该结点的度; 如上图:A的度为6 树的度:一棵树中,所有结点度的最大值称为树的度; 如上图:树的度为6 叶子结点或终端结点:度为0的结点称为叶结点; 如上图:B、C、H、I...等节点为叶结点 双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点; 如上图:A是B的父结点 孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点; 如上图:B是A的孩子结点 根结点:一棵树中,没有双亲结点的结点;如上图:A 结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推 树的高度或深度:树中结点的最大层次; 如上图:树的高度为4 树的深度和结点的层次是相同的 非终端结点或分支结点:度不为0的结点; 如上图:D、E、F、G...等节点为分支结点 兄弟结点:具有相同父结点的结点互称为兄弟结点; 如上图:B、C是兄弟结点 堂兄弟结点:双亲在同一层的结点互为堂兄弟;如上图:H、I互为兄弟结点 结点的祖先:从根到该结点所经分支上的所有结点;如上图:A是所有结点的祖先 子孙:以某结点为根的子树中任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙 森林:由m(m>=0)棵互不相交的树组成的集合称为森林 树的表示形式 树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,实际中树有很多种表示方式, 如: 双亲表示法 , 孩子表示法 、 孩子双亲表示法 、 孩子兄弟表示法 等等。我们这里就简单的了解 其中最常用的 孩子兄弟表示法 。 例子:

leetcode每日一题--矩阵中移动的最大次数

一.题目原型 二.思路解析 1.动态规划 这道题要求的是矩阵的最大移动次数。根据题目意思,从索引 0 列开始向右移动,每次移动一列,最多移动到 n - 1 列,也就是 n - 1次。其移动规则为:当前单元格可以移动到其右上方、正右方以及右下方三个位置中严格大于其的单元格。那么换个角度想,一个单元格可以从其左上方、正左方以及左下方的单元格转移过来。 这不就是我们动态规划最开始的典型思路吗? 在这题中,我们从第一列开始,往后能走多少,到了第几列,其实就是这一次的走的步数,走到最远的列,就是最大的移动次数。 我们创建一个二维dp数组,初始化为0,我们从不同行的第一列元素开始走,能走到的地方我们做一个标记为1,已经标记过的我们就不再去走了,以免死循环。 int m=grid.size(),n=grid[0].size(),max_j=0; vector<vector<int>>dp(m,vector<int>(n,0)); for(int i=0;i<m;++i){//初始化 dp[i][0]=1; } dp【i】【j】由dp【i-1】【j-1】和dp【i】【j-1】和dp【i+1】【j】决定 for(int j=1;j<n;++j){//从第1列开始 for(int i=0;i<m;++i){ if((dp[i][j-1]==1&&grid[i][j]>grid[i][j-1])||(i-1>-1&&dp[i-1][j-1]==1&&grid[i][j]>grid[i-1][j-1])||(i+1<m&&dp[i+1][j-1]==1&&grid[i][j]>grid[i+1][j-1])){ dp[i][j]=1; max_j=j; } } } 2.深度优先遍历 从第一列的任一单元格 (i,0)开始递归。枚举往右上/右/右下三个方向走,如果走一步后,没有出界,且格子值大于 grid[i][j],则可以走,继续递归。 在递归过程中,记录能访问到的最大列号,作为答案。 代码实现时,为避免重复递归之前访问过的格子,可以用一个 vis 数组标记访问过的格子。但实际上,可以把 grid[i][j]置为 0从而无需创建 vis数组。这是因为网格值均为正数,并且我们只能访问到比当前格子值更大的格子,所以置为 0 会导致永远无法访问到该格子,这正是我们所希望的。grid[i][j]置为0,表示这个点我们已经走过了,之后没有必要再走了,因为再往这个点走,移动的次数都是一样的。标记后就肯定不会再走了,因为要往后走的一个条件就是后面的点的值大于当前点的值。 function<void(int, int)> dfs = [&](int i, int j) { ans = max(ans, j); if (ans == n - 1) { // ans 已达到最大值 return; } // 向右上/右/右下走一步 for (int k = max(i - 1, 0); k < min(i + 2, m); k++) { if (grid[k][j + 1] > grid[i][j]) { dfs(k, j + 1); } } grid[i][j] = 0; }; 3.

rust引用-借用机制扩展

rust引用-借用机制还是有限制的,比如我们要在多次函数调用中修改参数、跨线程传递参数并发修改的场景,单纯使用引用-借用机制就不灵了(这种场景和引用-借用设计思想是冲突的)。这时需要借助rust提供的Rc、Arc、Cell、RefCell对机制来扩展默认的引用借用机制。 慢慢品味,std库里提供的很多实现,都是围绕引用-借用机制展开的;默认的引用-借用机制适合80%的场景,20%的场景还是需要额外的机制来扩展的(引入额外的性能开销,可能其中的15%可以通过优化设计避免)。 1、线程内 use std::rc::Rc; use std::cell::RefCell; fn main() { println!("Hello, world!"); let mut param = Param::default(); param.name = "xiao ming".to_string(); let rc_param = Rc::new(param); //Rc自带引用计数,可clone多个实例传给给函数作为参数,超出作用域引用计数减一至零时自动销毁 //Rc不能跨线程,要跨线程使用需要改为Arc+Mutex let rc1 = rc_param.clone(); let rc2 = rc_param.clone(); let rc3 = rc_param.clone(); println!("{}", rc1.name); new_value_fn1(rc2); new_value_fn2(rc3); //如果要在函数中修改参数的值,需要使用Rc+RecCell let mut param2 = Param::default(); param2.name = "小红".to_string(); let rc_refcell_param = Rc::new(RefCell::new(param2)); let rc_rec_p1 = rc_refcell_param.clone(); let rc_rec_p2 = rc_refcell_param.clone(); new_value_refcell_fn1(rc_rec_p1); new_value_refcell_fn2(rc_rec_p2); println!("{}", rc_refcell_param.borrow().name); //小红-fn1-fn2 } fn new_value_fn1(param: Rc<Param>){ println!

taskflow:多线程并行任务

文章目录 一、taskflow二、SunTaskFlow参考 一、taskflow 首先taskflow是基于graph的,每个独立的task只能在单核单线程上运行,可以看成一个执行单元。 task之间可以并行,那么taskflow和普通线程池的区别在于,可以给task之间添加依赖关系,比如taskA.precede(taskB) 表示taskB依赖taskA; 或者taskA.succeed(taskB) 表示taskA依赖taskB; (这个等价于taskB.precede(taskA)) 把每个task看成节点,依赖关系看成有向边,可以画出task 但是注意这个图不能有环形依赖;这个可以通过拓扑排序校验。 那么构建了这个依赖关系之后,taskflow的能力就是可以在尽可能多的并行处理前提下,保证有依赖的任务之间的调用顺序。 例如:B依赖A依赖S;那么taskflow会保证 B执行之前,A,S都已经指向完毕。 二、SunTaskFlow 参考 taskflow多线程并行任务实现思路SunTaskFlowtaskflowCGraph

Java SE String类 (三) : StringBuilder, StringBuffer与OJ例题

2. StringBuilder和StringBuffer 在上一篇博客我们提到,String类具有不可变性,在每次修改字符串的时候都是创建新的对象去修改,那么现在我们引入StringBuilder和StringBuffer类. 在用这两个类建立对象的时候, 字符串就是可变的, 可用类中的一些方法对字符串进行一系列操作,这两个大类的部分功能是相同的.这里介绍一些常用的方法,要是用到其他方法,大家可参考jdk帮助手册. 方法功能StringBuff append(String str)在尾部添加字符串,相当于String的+=char charAt(int index)获取index位置的字符int length()获取字符串的长度int capacity()获取字符串在底层储存空间的大小void ensureCapacity(int mininmumCapacity)扩容int setCharAt(int index,char ch)将index位置的字符设置为chint indexOf(String str)将index位置开始查找str第一次出现的位置int indexOf(String str,int index)从index位置开始向后查找str,返回第一次出现的位置int lastIndexOf(String str)从最后的位置开始查找指定字符串int lastIndexOf(String str,int index)从index位置开始查找指定字符串StringBuff insert(int index,String str)在index位置插入:八种基本类型,String类,Object类StringBuffer delete(int start,int end)删除[start,end)区间的字符串StirnBuffer deleteCharAt(int index)删除index位置的字符StringBuffer replace(int start,int end,String str)替换[start,end)区间的字符串String substring(int start)从start位置截取字符串,直到结尾,并以String类型返回String substring(int start, int end)将[start,end)范围字符串截取下来,并以String类型返回StringBuffer reverse()翻转字符串String toString()将所有字符串以String的方式返回下面进行上述方法的演示 public class Test { public static void main(String[] args) { StringBuilder sb1 = new StringBuilder("hello"); sb1.append(" world"); sb1.append(" !!!");//为sb1添加字符 System.out.println(sb1); System.out.println(sb1.charAt(2));//获取2位置的字符 System.

前端和后端权限控制【笔记】

前端权限设置【笔记】 前言版权推荐前端权限设置需求效果实现资源 后端权限控制1.给所有前端请求都携带token2.添加拦截器3.配置到WebMvcConfiguration4.更多的权限验证 最后 前言 2024-3-15 18:27:26 以下内容源自《【笔记】》 仅供学习交流使用 版权 禁止其他平台发布时删除以下此话 本文首次发布于CSDN平台 作者是CSDN@日星月云 博客主页是https://jsss-1.blog.csdn.net 禁止其他平台发布时删除以上此话 推荐 无 前端权限设置 需求 family权限的用户不能访问doctor/*.html … 效果 访问doctor/*.html弹出“你不是医生账户”, 重定向到home.html 实现 获取到当前路径currentURL 获取到当前用户角色userRole 判断这个路径是否是该角色能访问的 function onload(){ var currentURL = window.location.href; // console.log("当前页面路径是:" + currentURL); // console.log(userRole); var adminMatch = currentURL.match(/\/admin\//); if (adminMatch&&userRole!='admin'){ alertBox("你不是管理员账户",function(){ window.location.href="../home.html"; }); } var doctorMatch = currentURL.match(/\/doctor\//); if (doctorMatch&&userRole!='doctor'){ alertBox("你不是医生账户",function(){ window.location.href="../home.html"; }); } var familyMatch = currentURL.match(/\/family\//); if (familyMatch&&userRole!='family') { alertBox("你不是家属账户",function(){ window.location.href="../home.html"; }); } } 资源 模块结构

【LLMs+小羊驼】23.03.Vicuna: 类似GPT4的开源聊天机器人( 90%* ChatGPT Quality)

官方在线demo: https://chat.lmsys.org/ Github项目代码:https://github.com/lm-sys/FastChat 官方博客:Vicuna: An Open-Source Chatbot Impressing GPT-4 with 90% ChatGPT Quality 模型下载: https://huggingface.co/lmsys/vicuna-7b-v1.5 | 所有的模型 解读:量子位科技报道 | | 知乎陈城南 || GPT的一生 相关-斯坦福羊驼模型 Alpaca: A Strong, Replicable Instruction-Following Model 文章目录 一、简介1.1 什么是Vicuna(小羊驼)? (类似GPT4的开源聊天机器人)Vicuna1.5(LLaMA2上微调的)1.1.2 性能对比 1.2 GPT相关概念 ?1.2.1 GPT的4个阶段:1.2.2 什么是token? (字符切分的最小单位,1 token ~= 0.75 of word) 二 、本地部署 (linux服务器)本机环境:cuda12.1 + 3090ti模型和项目下载下载相关模型 安装依赖启动方式1:纯命令端 启动(不推荐)方式2:gradio ui对话 (启动3个服务 server 、model、gradio) 一、简介 1.1 什么是Vicuna(小羊驼)? (类似GPT4的开源聊天机器人) Vicuna(音标 vɪˈkjuːnə ,小羊驼、骆马) 是 基于LLaMA的指令**微调**模型 (类似GPT的文本生成模型) LLaMA: 是基础大语言模型,用大量质量一般的互联网文本数据训练,与GPT3 、PaLM类似

服务器数据恢复—服务器硬盘灯显示红色的数据恢复案例

服务器数据恢复环境&故障: 一台服务器中有一组由多块硬盘组建的raid阵列,在运行过程中服务器突然崩溃,管理员检查服务器发现该服务器raid阵列中有两块硬盘的指示灯显示红色。于是,管理员重启服务器,服务器重启后,先离线的硬盘上线并开始自动同步数据,数据同步过程中管理员又将服务器强制关机。 服务器数据恢复过程: 1、北亚企安数据恢复工程师拿到故障服务器后,将故障服务器中所有磁盘编号后取出,经过硬件工程师检查,发现所有磁盘都可以正常读取,没有明显的硬件故障。于是,服务器数据恢复工程师将所有磁盘以只读方式进行全盘镜像。镜像完成后按照编号将所有磁盘还原到原服务器中,后续的数据分析和数据恢复操作都基于镜像文件进行,避免对原始磁盘数据造成二次破坏。 2、基于镜像文件分析底层数据,根据分析获取到的raid相关信息虚拟重构raid阵列并进行异或校验,经过校验发现有一部分数据破坏。经过仔细分析发现数据被破坏的原因是重启服务器后先离线的硬盘上线进行了数据同步。 3、服务器数据恢复工程师尝试了多种不同方法提取数据,但是结果都是一样的,每次提取后都发现有部分数据被破坏,数据提取不完整。 4、服务器数据恢复工程师使用工具对数据文件进行扫描并进行人工分析,不幸的是由于服务器有过同步的操作,数据文件的目录遭到破坏,已经不可见了。 5、由于数据文件的目录丢失,服务器数据恢复工程师只能对自由分区空间进行扫描,扫描出了大量的文件碎片,经过漫长的分析和聚合工作后,北亚企安数据恢复工程师提取出数据,对新提取的数据进行验证没有发现问题。 6、服务器数据恢复工程师让用户方验收数据,经过用户方仔细验证,确认服务器中丢失的所有数据均已恢复,本次服务器数据恢复工作完成。

基于 Java Web 项目的 SpringBoot 框架初始化模板

项目Github地址:https://github.com/AntonyCheng/spring-boot-init-template,模板介绍如下: 作者:AntonyCheng 版本号:v2.1.1 开源协议:Apache License 2.0 SpringBoot初始化模板 基于 Java Web 项目的 SpringBoot 框架初始化模板,该模板整合了常用的框架,保证大家在此基础上能够快速开发自己的项目,该模板针对于后端启动开发小而精,本项目会由作者持续更新。 模板特点 主流框架 Java 11 兼容性,详情见兼容Java8 SpringBoot 2.7.18 spring-boot-starter-web == 基于 Spring MVC 的 Web 应用依赖spring-boot-starter-undertow == 轻量级、高性能 Servlet 容器spring-boot-starter-aop == 提供面向切面编程功能spring-boot-starter-validation == 参数校验依赖spring-boot-starter-data-mongodb == Spring Data MongoDB 依赖spring-boot-starter-email == Spring Data Email 依赖spring-boot-starter-freemaker == 模板引擎依赖spring-boot-starter-test == Spring Boot Test 依赖spring-boot-configuration-processor == 生成配置元数据信息,辅助开发工具 Netty netty-all 4.1.107.Final == Netty 框架 MySQL mysql-connector-j 8.0.33 == Java 连接 MySQL 依赖mybatis-plus-boot-starter 3.

java 数据结构 优先级队列(PriorityQueue)

目录 优先级队列 堆的概念 堆的性质 堆的存储方式 堆的创建 堆的插入 堆的删除 用堆模拟实现优先级队列 PriorityQueue的特性 PriorityQueue常用接口介绍 堆排序 优先级队列 前面介绍过队列,队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优 先级,一般出队 列时,可能需要优先级高的元素先出队列,该中场景下,使用队列显然不合适, 比如:在手机上玩游戏的时候,如 果有来电,那么系统应该优先处理打进来的电话;初中那会班 主任排座位时可能会让成绩好的同学先挑座位。 在这种情况下,数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新 的对象。这种数据结构就是优先级队列(Priority Queue)。 PriorityQueue底层使用了堆这种数据结构,而堆实际就是在完全二叉树的基础上进行了一些调整 堆的概念 如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储 方式存储 在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫 做最小堆或小根堆 堆的性质 1.堆中某个节点的值总是不大于或不小于其父节点的值; 2.堆总是一棵完全二叉树 堆的存储方式 从堆的概念可知,堆是一棵完全二叉树,因此可以层序的规则采用顺序的方式来高效存储, 注意:对于非完全二叉树,则不适合使用顺序方式进行存储,因为为了能够还原二叉树,空间中必须要存储空节点,就会导致空间利用率比较低。 将元素存储到数组中后,可以根据二叉树章节的性质5对树进行还原。假设i为节点在数组中的下标,则有: 如果i为0,则i表示的节点为根节点,否则i节点的双亲节点为 (i - 1)/2 如果2 * i + 1 小于节点个数,则节点i的左孩子下标为2 * i + 1,否则没有左孩子 如果2 * i + 2 小于节点个数,则节点i的右孩子下标为2 * i + 2,否则没有右孩子