删除链表中等于给定值 val 的所有结点(三种方法深入解析)

又见面啦,接下来的链表相关Oj题目我会根据我自己的理解来给大家讲解,包括解析和代码,希望你可以对链表有更加深入的理解!! 题目: 先上链接: OJ题目 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。 方法一:迭代 想法:遍历链表,找到这个val前面一个结点,让这个结点指向val的next 注意:在寻找为给定值的结点时,需要先判断结点是否为空结点 if (head != nullptr && head->val == val) { head = head->next; } 结果如下: struct ListNode* removeElements(struct ListNode* head, int val) { if (head != nullptr && head->val == val) { head = head->next; } if(NULL==head){ return head; } struct ListNode*pre=head; while(pre->next!=NULL) { if(pre->next->val==val) { pre->next=pre->next->next; } else { pre=pre->next; } } return head; } 方法二:双指针 设置两个指针,值为head

DS:链表的分类

欢迎来到Harper.Lee的学习世界! 博主主页传送门:Harper.Lee的博客主页 想要一起进步的uu欢迎来后台找我哦! 链表的结构⾮常多样,以下情况组合起来就有8种(2 * 2 * 2)链表结构。下面我们依次来认识它们吧! 一、带头或者不带头 带头:指的是链表中有哨兵位,该哨兵位节点就是头节点。在前面实现单链表的文章中,口头上提到的头节点实际上指的是链表的第一个有效的节点,这其实不是正确的称呼。但是为了便于理解而采用了“头节点”这个称呼。实际上在链表中,头节点指的是哨兵位。 二、双向或者单向 虽然双向链表的结构看上去要比单链表复杂得多,实际上双向链表的实现比单链表简单的多,代码也相对较少。 三、循环或者不循环 判断链表是否为循环链表:尾节点的next指针是否为空 之前实现的链表叫做单链表,它的全称为:不带头单向不循环链表;常用的链表还有双向链表,它的全称为:带头双向循环链表,和单链表完全相反。 喜欢的uu记得三连支持一下哦!

python安卓自动化pyaibote实践------学习通自动刷课

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文是一个完成一个自动播放课程,避免人为频繁点击脚本的构思与源码。 加油!为实现全部电脑自动化办公而奋斗! 为实现摆烂躺平的人生而奋斗!!! 环境描述 aibote,雷电模拟器,学习通,python3.12,pyaibote框架。 环境不会搭建可以看我这篇博客:pyaibote--安卓自动化环境配置与基础的使用方法_aibote链接手机-CSDN博客 成品代码 from PyAibote import AndroidBotMain import time # 2. 自定义一个脚本类,继承 AndroidBotMain class CustomAndroidScript(AndroidBotMain): #初始化配置 Log_Level = "DEBUG" Log_Storage = True def start_xuexitong(self): #打开学习通,进入看课区域 result = self.start_app("学习通", 5, 0.5) print("app运行状态:{}".format(result)) place=self.get_element_rect("com.chaoxing.mobile/com.chaoxing.mobile:id=tabButton[3]", 15, 0.5) self.click((place)) print("点击任务状态:{}".format(place)) place=self.get_element_rect("com.chaoxing.mobile/com.chaoxing.mobile:id=myCourse", 15, 0.5) self.click((place)) print("点击任务状态:{}".format(place)) def select_class(self): #选择目标课程,并且判断是否有课程 self.my_class=input("输入想要刷课的名称:") result = self.init_ocr_server("127.0.0.1", False, False, False) print("初始化状态:{}".format(result)) result = self.get_text() print(result) if self.my_class in result: print("发现目标课程") result = self.

【redis】redix在Linux下的环境配置和redis的全局命令

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶​ 个人主页:xiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 系列专栏:​ xiaoxie的redis学习系列专栏——CSDN博客●'ᴗ'σσணღ ​ 我的目标:"团团等我💪( ◡̀_◡́ ҂)" ( ⸝⸝⸝›ᴥ‹⸝⸝⸝ )欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​+关注(互三必回)! 目录 ​编辑 一.redix在Linux下的环境配置 1.基于Centos下的环境配置 1.使用yum安装 2.构建符号链接 3.针对配置⽂件设置符号链接 4.修改配置文件 1.打开配置文件 2.设置 IP 地址 3.关闭保护模式 4.启动守护进程 ​编辑 5.设置工作目录和日志目录 5.启动 redis 1.启动redis服务器 2.打开redis的客服端 6.停⽌ redis服务器 2.基于Ubuntu下的环境配置 二.redis的全局命令 1.get 和 set 2.keys 1.? 匹配任意一个字符 2. * 匹配任意多个字符包括0个 ​编辑 3.[a,b,c]只能匹配括号里面的字符 4.[^e] 排除括号里的字符 5.[a-d]匹配字符a到字符d之间的字符,前闭后闭 ​编辑 6.注意事项 3.exists 4.del

MySQL 8.4 版本(LTS) 发布,一睹为快

前言 Oracle 前几天发布了 MySQL 8.4 版本(LTS), 该版本是创新版的第一个长期支持版本。详细规划,请移步 技术译文 | 一文了解 MySQL 全新版本模型 关于 MySQL 的版本发布规划 Oracle MySQL 官方开发团队推出的新版本将过渡到新的 MySQL 版本模型。MySQL 8.1.0 是第一个创新版本,8.0.34+ 将只进行错误修复,直到 8.0 生命周期结束(EOL,定于 2026 年 4 月)。 MySQL 8.x 版本最终将成为 LTS,这将为用户从 8.0.x 迁移到 8.x LTS 版本提供充足的时间。 对我们的影响 ,总结起来就是: 如果用户想要 MySQL 数据库的最新功能、改进和bug fix,请使用创新版本(例如 8.1.x、8.2.x、8.3.x 等)。 如果用户 MySQL 只需要错误修复,请使用 8.0.x 版本(例如 8.0.35、8.0.36、8.0.37 等)。 如果用户使用的是国内云厂商的RDS MySQL 数据库服务,具体版本支持计划请参考各个厂商的相关公告。 言归正传,聊聊 8.4 的技术特性。 8.4 功能变更 1 MySQL 密码认证 认证插件:默认情况下, mysql_native_password 插件被禁用, 如果需要启用该插件,需要在启动时指定 --mysql-native-password=ON 或者在my.

未来科技的前沿:深入探讨人工智能的进展、机器学习技术和未来趋势

文章目录 一、人工智能的定义和概述1. 人工智能的基本概念2. 人工智能的发展历史 二、技术深入:机器学习、深度学习和神经网络1. 机器学习2. 深度学习3. 神经网络 三、人工智能的主要目标和功能1. 自动化和效率提升2. 决策支持和风险管理3. 个性化服务和预测未来 本文将探索人工智能技术的演变,着重分析其核心技术和应用,理解这一技术如何重塑现代社会与经济。 一、人工智能的定义和概述 人工智能(Artificial Intelligence, AI)作为21世纪最具变革性的科技领域之一,已经成为现代社会和科技进步的一个核心组成部分。它涉及设计智能机器,特别是智能计算机程序,其核心在于模仿和扩展人类的认知功能。 1. 人工智能的基本概念 人工智能的定义涉及到机器的智能行为,尤其是计算机执行通常需要人类智能的任务,如视觉识别、语言理解、决策和学习。简而言之,AI的目标是创建能够自主进行这些高级任务的机器,同时在特定情况下,甚至超越人类的能力。 这些智能系统的核心目的在于模仿人类大脑处理和解析信息的方式,从而扩展人类的认知功能。通过这种模仿,AI系统不仅可以执行复杂任务,还可以通过学习和适应,持续改进其性能。 2. 人工智能的发展历史 人工智能的概念可以追溯到古代神话中的自动机和机械人,但现代AI的起点通常认为是1950年代。1950年,艾伦·图灵发表了其著名的论文《计算机器与智能》,提出了“图灵测试”作为判断机器是否能够思考的标准。此后,这个领域逐渐展开,经历了几次冬天和复苏期,每一次都使AI技术更加成熟。 到了20世纪末,随着计算能力的显著提高和数据量的爆炸式增长,人工智能开始快速发展。1997年,IBM的深蓝计算机在国际象棋比赛中战胜了世界冠军加里·卡斯帕罗夫,成为历史上第一次在此类比赛中战胜人类冠军的计算机系统。这一事件标志着AI实用化的重要里程碑。 进入21世纪,随着机器学习特别是深度学习技术的兴起,人工智能的应用变得越来越广泛,影响到从自动驾驶汽车到医疗诊断的各个领域。2016年,谷歌的AlphaGo在围棋比赛中战胜了世界冠军李世石,这再次显示了AI在解决复杂问题上的惊人能力。 二、技术深入:机器学习、深度学习和神经网络 人工智能的三个核心技术:机器学习、深度学习和神经网络。这些技术构成了现代AI系统的基础,并且彼此之间紧密相关,共同推动了人工智能领域的快速发展。 1. 机器学习 机器学习是人工智能的一个重要分支,它使计算机能够通过数据和算法自我学习和改进,而无需进行明确的程序编码。机器学习的核心在于开发算法,让机器从数据中自动学习模式和决策逻辑。 原理和方法: 机器学习方法通常分为监督学习、无监督学习和强化学习: 监督学习涉及到预先标记的数据,机器通过学习输入与输出之间的关系来预测新的数据点。无监督学习不依赖于标签数据,而是寻找数据本身的结构和关联。强化学习则是通过奖励和惩罚机制,使机器在环境中自我学习最佳行为策略。 实用工具: Scikit-learn 是一个广泛使用的Python库,提供了各种机器学习工具,适用于数据挖掘和数据分析。它被广泛应用于教育和工业界,为初学者和专业人士提供了丰富的机器学习算法实现。 应用实例: 例如,电子邮件服务中的垃圾邮件过滤器就是机器学习的应用之一。系统通过分析成千上万个例子,学习何种类型的邮件属于垃圾邮件,进而有效地过滤掉这些不必要的信息。 2. 深度学习 深度学习是机器学习的一个子集,它通过模拟人脑的结构和功能来建立复杂的算法模型,称为神经网络。深度学习在处理非结构化数据(如图像、声音和文本)方面表现出了卓越的能力。 与传统机器学习的区别: 深度学习模型能够自动从大量数据中提取高级特征,而传统机器学习模型则通常需要人工设计特征提取方式。这使得深度学习在许多复杂任务上,如图像识别和语音识别,表现更为优越。 神经网络工作原理: 深层神经网络由多层的节点(神经元)组成,每一层通过非线性变换处理信息,并传递到下一层。通过大量的数据训练和适当的调整网络参数(权重和偏置),网络能够学习到如何准确地执行分类或预测任务。 实用工具: PyTorch 是一个开源的机器学习库,广泛用于应用程序如计算机视觉和自然语言处理中的深度学习模型。它由Facebook的AI研究团队开发,以其灵活性和速度被众多研究者和开发者所青睐。 3. 神经网络 神经网络是实现深度学习的基础技术之一。它们的结构受到人脑神经元的启发,由成千上万的连接点构成,每个连接点都可以传递信息。 结构和功能: 神经网络的基本单位是神经元,每个神经元接收来自前一层的输入,进行加权求和,并通过一个非线性函数(激活函数)输出到下一层。这种结构使得神经网络特别适合处理复杂的模式识别任务。 不同类型及其应用: 卷积神经网络(CNN) 主要用于处理图像。循环神经网络(RNN) 优于处理序列数据,如时间序列分析和自然语言处理。生成对抗网络(GAN) 在图像生成和视频游戏中有广泛应用。 三、人工智能的主要目标和功能 人工智能的目标不仅是提高效率和准确性,还包括帮助做出更好的决策、提供个性化服务和预测未来事件。 1. 自动化和效率提升 人工智能在自动化领域的应用极大地提高了多个行业的工作效率和准确性。通过替代重复性高且耗时的任务,AI使企业能够将人力资源重新分配到需要更多创造力和人类决策能力的领域。 制造业:AI驱动的机器人可以24小时不间断地在生产线上工作,不仅提高了生产效率,还减少了人为错误。服务行业:例如,AI在呼叫中心通过自然语言处理技术自动处理客户请求,减轻了人工客服的压力,并提高了响应速度和服务质量。 2. 决策支持和风险管理 AI系统能够分析复杂数据集,提供即时的洞察力,辅助企业和个人做出基于数据的决策。在风险管理方面,AI通过预测分析帮助识别潜在的风险点,从而采取预防措施,减少损失。 金融服务:在信贷审批过程中,AI可以分析申请者的信用历史、消费行为和其他相关数据,快速准确地评估贷款风险。医疗健康:AI在处理病历数据时能够识别疾病模式,提前警告医生关于患者潜在健康问题,从而实现早期干预。 3.

JSP语法——[JSP]5

希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,大大会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要! 目录 前言 Java 程序片 Java表达式 JSP中的注释 JSP指令标记 总结 前言 主要内容 JSP页面的基本结构 声明变量和定义方法 Java程序片 Java表达式 JSP指令标记 JSP动作标记 难点 Java程序片 JSP动作标记 关键实践 消费总和 听英语 Java 程序片 例子2 4中,通过synchronized方法操作一个成员变量来实现一个简单的计数器。 例子2-4 example2 4.jsp 可以将一个Java程序片分割成几个Java程序片, 然后在这些Java程序片之 间再插入其他标记元素。在程序片中插入HTML中的标记的技巧对于灵活显 示数据是非常重要的。 例子2 5获得一个7至19之间的随机数,如果获得的数小于或等于13就显示一幅小学 生的图像,否则显示一幅中学生的图像。显示图像需要在程序片之间插入用于显示 图像的 <image src=图像的URL>文字说明</image> 的HTML标记 例子2_5 Java表达式 <=%…· …·%> 可以在<%=和%>之间插入一个可求值的表达式(注意:不可插入语句,<%=是一个完整的符号,<%”和“=”之间不要有空格)。 ★表达式的值由服务器负责计算,并将计算结果用字符串形式发送到用户端显示。 ★Java表达式可以写在<HTML>之前,也可以写在<HTML>和</HTML>之间或</HTML>之后。 在JSP页面中,表达式的值被表示成一个字符串的形式,即Tomcat服务器将表达式的结果转换成字符串,然后发送给用户的浏览器。因此,在编写ISP页面时,要把Java表达式按普通的文本来使用。 例子2 6 JSP中的注释 注释可以增强JSP页面的可读性,使ISP页面易于维护。ISP页面中的注释可分为两种。 HTML注释:在标记符号“<!--”和“-->”之间加入注释内容: <!--注释内容 --> ISP引擎把HTML注释交给用户,因此用户通过浏览器查看JSP页面的源文件时能够看到HTML注释。 <%--...--%> JSP 注释:在标记符号“<%--和“--%>”之间加入注释内容: <%-注释内容 --%> Tomcat服务器忽略JSP注释,即在编译JSP页面时忽略ISP注释。 例子2 7使用了HTML和JSP注释 例子27 example2 7.

C语言数据在内存中的存储

C语言数据在内存中的存储 个人主页:大白的编程日记 个人专栏:C语言学习之路 文章目录 C语言数据在内存中的存储前言一.整数在内存中的存储1.1整数的表示形式1.2整数在内存中的存放 二.大小端字节序和字节序判断2.1大小端的概念2.2为什么有大小端 三.练习3.1整型提升3.2算术转换3.3练习一(百度笔试题)3.4练习二3.5练习三3.6练习四3.7练习五3.8练习六 四.浮点数在内存中的存储4.1练习4.2浮点数的存储4.3浮点数存的过程4.4浮点数取的过程 后言 前言 哈喽,各位小伙伴大家好!我们都知道计算机的数据都是存储在内存中的。那它是如何存储,以什么形式存储,存储方法又是什么呢?今天小编就带着大家一起去学习数据在内存中的存储。向着大厂冲锋! 一.整数在内存中的存储 1.1整数的表示形式 整数的2进制表示方法有三种,即原码、反码和补码。 三种表示方法均有符号位和数值位两部分, 符号位都是用0表示“正”,用1表示“负”, 而数值位最高位的⼀位是被当做符号位,剩余的都是数值位。 正数: 正整数的原、反、补码都相同。 负数: 负整数的三种表示方法各不相同。 原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。 反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。 补码:反码+1就得到补码。 注意,补码转原码有两种方式。 一:先-1后取反。 二:先取反后+1。 1.2整数在内存中的存放 对于整形来说:数据存放内存中其实存放的是补码。 在计算机系统中,数值⼀律⽤补码来表示和存储。 为什么呢? 使用补码,可以将符号位和数值域统⼀处理。加法和减法也可以统⼀处理(CPU只有加法器),可以将减法转化为加法运算。这是用原码计算是错误的,使用补码才能正确运算。 补码与原码相互转换,其运算过程是相同的,都可以按取反+1转化,不需要额外的硬件电路。 二.大小端字节序和字节序判断 当我们了解了整数在内存中存储后,我们调试看⼀个细节: #include <stdio.h> int main() { int a = 0x11223344; return 0; } 调试的时候,我们可以看到在a中的 0x11223344 这个数字是按照字节为单位,倒着存储的。 这是为什么呢? 这就涉及到大小段字节序的问题了。 2.1大小端的概念 其实超过⼀个字节的数据在内存中存储的时候,就有存储顺序的问题。 我们来想一个问题 #include <stdio.h> int main() { int a = 0x11223344; return 0; } 如果我们要把a存在内存里我们该怎么存。 比如这四种存放顺序。

JSP简介——[JSP]2

希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,大大会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要! 目录 前言 JSP页面 设置web服务目录 1.根目录 2.webapps下的Web服务录 3.新建Web服务目录 4.相对目录 1.4JSP运行原理 总结 前言 主要内容 JSP页面 设置web服务目录 必须将编写好的JSP页面文件保存到Tomcat服务器的某个Web服务目录中,只有这样,远程的用户才可以通过浏览器访问该Tomcat服务器上的JSP页面。人们常说的一个网站,实际就是一个Web服务目录。 1.根目录 如果Tomcat服务器的安装目录是D:\apache-tomcat-8.0.3,那么Tomcat的Web服务目录的根目录是D:apache-tomcat-8.0.3\webapps Root.用户用以下两种方式可以访问根目录下的JSP页面example1 1.jsp.Tomcat服务器的IP地址是192.168.1.100,可以在浏览器输入Tomcat服务器的IP地址(或域名)、端口号和JSP页面的名字即可(必须省略Web根目录的名字) http://192.168.1.100:8080/example1 1.jsp 没有为Tomcat服务器所在的机器设置过一个有效的IP地址,在浏览器输入的内容是 http://127.0.0.1:8080/example1 1.jsp 2.webapps下的Web服务录 Tomcat服务器安装目录webapps下的任何一个子目录都可以作为一个Web服务日录。比如在webapps下新建子目录ch1,那么ch1就成为一个Web服务目录。将ISP页面文件保webapps下的Web服务目录中那么应当在浏览器器的地址栏中输入Tomcat服务器的IP地址(或域名),端口号、Web服务目录和JSP页面的名字比如example1 1.jsp保存到D:\apache-tomcat-8.0.3\webappsch1中,那么,浏览器的地址栏中输入的内容为: http://127.0.0.1:8080/ch1/example1 1.jsp 效果如图1.8所示。 3.新建Web服务目录 可以将Tomcat服务器所在计算机的某个目录(非webapps下的子目录)设置成一个Web服务目录,并为该Web服务目录指定虚拟目录,即隐藏Web服务目录的实际位置,用户只能通过虚拟目录访问Web服务目录中的JSP页面。 例如:将example1 1.jsp保存到任意日录如D:\MyBook\zhang以及C:\wang中,并让用户分别使用apple和cloud虚拟目录访问此Web服务目录,那么 1)用记事本打开conf文件夹中的主配置文件server.xml,在 </Host>的前面加入: <Context path="/apple" docBase="D:\MyBook\zhang" debug="0" reloadable="true" /> <Context path="/cloud" docBase="C: wang" debug="0" reloadable="true" /> 2)保存并重新启动 tomcat服务器、 在浏览器的地址栏中输入http://127.0.0.1:8080/apple/example1_1.jsp或 http://127.0.0.1:8080/cloud/example1 1.jsp就可以正确的访问 D:MyBook\zhang以及c:wang中example1 1.jsp页面。 4.相对目录 Web服务目录的下的目录称为该Web服务目录下的相对web服务目录。 比如,我们可以在Web服务目录D:\MyBook\zhang下再建立一个子目录image,example11.jsp文件保存到image中。 那么可以在浏览器的地址栏中输入http://127.0.0.1:8080/apple/image/example1 1.jsp来访问examplel_1.jsp。 1.4JSP运行原理 当服务器上的一个JSP页面被第一次请求执行时,服务器上的JSP引擎首先将JSP页面文件转译成一个java文件,并编译这个java文件生成字节码文件,然后执行字节码文件响应客户的请求。 *把JSP页面中普通的HTML标记符号交给客户的浏览器执行显示。 *负责处理,JSP标记,并将有关的处理结果发送到客户的浏览器 *执行“<%”和“%”之间的Java程序片(JSP页面中的动态部分),并把执行结果交给客户的浏览器显示。

Mac 安装 JDK21 流程

一、下载JDK21 访问Oracle官方网站或选择OpenJDK作为替代品。Oracle JDK从11版本开始是商业的,可能需要支付费用。OpenJDK是一个免费开源选项。 Oracle JDK官方网站:Oracle JDK Downloads OpenJDK官方网站:OpenJDK Downloads 这里以JDK21为例: 我选择的是JDK21进行安装:ARM64和X64代表CPU架构类型,执行uname -m命令可以查看电脑是什么类型的cpu架构,选择对应的包,不匹配会提示安装失败或者不可用; bin.tar.gz和dmg包的区别: tar.gz直接解压就可以用,解压的路径就是安装的路径; dmg是mac安装文件规范,默认会安装到/Library/Java/JavaVirtualMachines/路径下; 二、安装JDK 进入下载目录,解压文件并将文件移动到指定的目录中。因为我们是手动安装,所以需要自己创建~/Library/Java/JavaVirtualMachines目录,我这里保持和自动安装的目录相同。 cd ~/Downloads # 记得将命令中的`openjdk-21.0.2_macos-x64_bin.tar.gz`、`jdk-21.0.2.jdk` 修改为你实际的名称: tar -zxf openjdk-21.0.2_macos-x64_bin.tar.gz mv jdk-21.0.2.jdk ~/Library/Java/JavaVirtualMachines 三、设置环境变量 使用终端编辑你的shell配置文件(如~/.bash_profile、~/.bashrc或~/.zshrc等),我们选择~/.zshrc文件,在文件末尾加入以下内容:第一行设置了JAVA_HOME环境变量,指向JDK 21的安装目录。第二行将JDK 21的bin目录添加到了PATH环境变量中,以便在终端中直接使用Java命令。 # 记得将命令中的`jdk-21.0.2.jdk` 修改为你实际的名称: export JAVA_HOME="~/Library/Java/JavaVirtualMachines/jdk-21.0.2.jdk/Contents/Home" export PATH=$JAVA_HOME/bin:$PATH 2、应用配置:source ~/.zshrc。 四、验证安装 打开命令行界面,运行以下命令: java -version javac -version 如果显示了java和javac的版本信息,而不是错误消息,则表明JDK已成功安装。

Python 植物大战僵尸

文章目录 效果图项目结构实现思路源代码 效果图 项目结构 实现思路 下面是代码的实现思路: 导入必要的库和模块:首先,我们导入了Python的os、time库以及pygame库,还有植物大战僵尸游戏中用到的各个植物和僵尸的类。 初始化游戏和加载资源:接下来,我们初始化了Pygame库,并设置了游戏的背景尺寸。然后,我们加载了游戏所需的各种图像资源,包括背景、植物、僵尸等。 定义游戏元素和变量:我们定义了几个全局变量,包括阳光值、植物组、子弹组、僵尸组和阳光组。还定义了一些特殊事件,用于在游戏中生成新的植物、子弹、僵尸和阳光等。 编写游戏主循环:游戏的主循环在main()函数中。在主循环中,我们首先更新了植物、子弹和僵尸的位置和状态,然后在屏幕上绘制了这些元素。接下来,我们响应了用户的鼠标和键盘事件,包括选择植物、放置植物、收集阳光等。最后,我们更新了游戏界面并检查了游戏是否结束。 处理游戏事件:在主循环中,我们使用pygame.event.get()函数获取当前的游戏事件,并根据事件类型进行相应的处理。例如,当用户点击鼠标时,我们会判断用户是否点击了植物种子的图标,如果是,则将选择的植物类型设置为相应的值;如果用户点击了游戏区域,则根据选择的植物类型放置植物。 更新游戏状态和界面:在主循环中,我们还更新了游戏的状态,如减少阳光值、增加僵尸数量等。同时,我们也更新了游戏界面,如重新绘制阳光值、植物、僵尸等。 检查游戏结束条件:在主循环中,我们还检查了游戏是否结束。如果僵尸到达了终点,则游戏失败;如果僵尸数量大于一定值,则游戏胜利。 启动游戏:最后,我们在if __name__ == '__main__':代码块中调用了main()函数,启动游戏。 玩家可以选择不同的植物来抵御僵尸的进攻,并收集阳光来购买更多的植物。游戏通过不断生成新的僵尸和植物,以及响应用户的操作,来保持游戏的进行,直到游戏结束。 源代码 完整代码地址:https://gitcode.com/stormsha1/games/overview pvz/main.py import os import time import pygame from pvz.plant.Peashooter import Peashooter from pvz.plant.SunFlower import SunFlower from pvz.plant.WallNut import WallNut from pvz.plant.Sun import Sun from pvz.plant.Sun2 import Sun2 from pvz.plant.JXC import JXC from pvz.plant.Bullet import Bullet from pvz.plant.BulletJXC import BulletJXC from pvz.zombie.Zombie import Zombie from pvz.zombie.ZombieLz import ZombieLz # 初始化pygame库 pygame.

Vue前端环境准备

vue-cli Vue-cli是Vue官方提供的脚手架,用于快速生成一个Vue项目模板 提供功能: 统一的目录结构 本地调试 热部署 单元测试 集成打包上线 依赖环境:NodeJs 安装NodeJs与Vue-Cli 1、安装nodejs(已经安装就不用了) node-v.msi 2、验证 cmd-->node -v 3、配置npm的全局安装路径 管理员身份运行cmd #设置为NodeJs安装目录 npm config set prefix "D:\Program Files\nodejs\node-global" #验证设置是否成功 npm config get prefix 4、切换npm淘宝镜像(优化下载) 管理员身份运行cmd npm config set registry https://registry.npmmirror.com 5、安装vue-cli 管理员身份运行cmd npm install -g @vue/cli #验证安装 vue --version 项目构建 1、新建工程文件 2、在该目录启动cmd/ vscode 3、创建vue项目 vue create vue-project 或者调出图形化界面创建:vue ui 项目目录介绍 node_modules 整个项目的依赖包 public 项目的静态文件 src 项目源代码 asssets静态资源 components可重用的组件 router路由配置 views视图组件(页面) App.vue入口页面(根组件) main.js入口js文件 package.json 模板基本信息,项目开发所需要模板,版本信息

探索AIGC技术:创新、挑战与责任

🎥 个人主页:Dikz12📕格言:那些在暗处执拗生长的花,终有一日会馥郁传香欢迎大家👍点赞✍评论⭐收藏 #如何看待AIGC技术? 目录 AIGC简单介绍 创新 责任 未来展望和挑战 AIGC简单介绍 AIGC是人工智能(AI)、算法(Algorithms)、机器学习(Machine Learning)和数据挖掘(Data Mining)技术的缩写。这些技术在计算机科学领域中发挥着重要作用,用于处理和分析数据、实现自动化决策和预测,以及优化各种应用程序和系统。AIGC技术的发展已经在多个领域产生了深远影响,包括自然语言处理、图像识别、智能推荐系统等。 创新 AIGC技术的结合确实为医学、农业和生物科学等领域带来了巨大的潜力和机遇。 医学领域: 基因编辑治疗:AIGC技术可以用于治疗各种遗传性疾病,如囊性纤维化、遗传性失明等。癌症治疗:通过AIGC技术可以进行精准的基因编辑,针对癌症细胞实现个体化治疗。新药开发:AIGC技术可以用于模拟疾病模型、筛选药物靶点,加速新药研发过程。 农业领域: 作物改良:利用AIGC技术可以编辑作物基因,增强抗病性、耐旱性和产量,推动粮食安全和农业可持续发展。畜禽养殖:通过编辑畜禽基因,改善生长速度、品质和抗病能力,提高养殖效率。 生物科学领域: 基因功能研究:AIGC技术可以帮助科学家深入了解基因在生物体内的功能和相互作用。疾病研究:利用AIGC技术可以建立疾病模型,加速对疾病机制的研究,为新药开发提供重要参考。 未来社会的影响和可能发展方向包括: 医疗水平提升:AIGC技术有望推动个性化医疗的发展,提高疾病治疗效果,延长人类寿命。农业生产革命:作物和畜禽基因编辑的广泛应用,有望解决粮食安全和养殖业可持续发展面临的挑战。生物科学突破:AIGC技术将加速基因功能和疾病机制的研究,推动生物科学领域的进步。道德和伦理问题:随着AIGC技术的应用不断扩大,涉及到基因编辑的伦理和道德问题也将引起社会广泛关注。 责任 隐私和数据安全: 问题:个人数据的大规模收集和分析可能侵犯个人隐私,导致数据泄露和滥用。应对措施:加强数据保护法律法规的制定和执行,确保个人数据的合法、公正和安全使用。推动隐私保护技术的研发和应用,如加密、数据匿名化等。 算法偏差和不公平: 问题:算法的设计和训练数据可能存在偏差,导致对某些群体的歧视和不公平对待。应对措施:加强算法的透明度和可解释性,确保算法的设计和运行过程公开透明。对算法进行审查和监督,确保其公平性和公正性。推动多样化的数据集和算法训练,减少偏差的产生。 就业和社会影响: 问题:AIGC技术的发展可能导致部分岗位的消失,加剧社会贫富差距,产生就业压力和社会不稳定。应对措施:加强教育和技能培训,为人们提供适应新技术环境的能力。推动政府和企业制定社会责任政策,包括重新分配就业机会、提供转岗培训等措施。 道德和伦理问题: 问题:AIGC技术的应用可能带来一些道德和伦理困境,如自动化决策的公平性、智能系统的责任问题等。应对措施:加强对AIGC技术的伦理审查和道德指导,确保其发展和应用符合道德准则和社会价值观。建立独立的伦理委员会和监督机构,对AIGC技术的发展和应用进行监督和评估。 未来展望和挑战 人工智能生成内容(AIGC)技术在未来的发展方向可能包括更加智能化的生成模型,具备更强大的语言理解和创造能力,以及更高的生成质量和多样性。潜在可能性包括提高内容创作效率,推动个性化内容推荐,增强虚拟助手的功能,以及创造全新的艺术和娱乐形式。然而,AIGC技术也带来一些挑战和影响,包括信息真实性和可信度的问题,隐私和数据安全的风险,以及对人类创造力和就业市场的影响。解决这些挑战需要采取综合性的措施,包括技术研发和监管政策的制定,加强用户教育和意识提升,以及促进技术与人类价值观的和谐发展。

【数据结构】链表专题3

前言 本篇博客我们继续来讨论链表专题,今天的链表算法题是经典中的经典 💓 个人主页:小张同学zkf ⏩ 文章专栏:数据结构 若有问题 评论区见📝 🎉欢迎大家点赞👍收藏⭐文章 目录 1.判断链表是否有环 2.返回入环的第一个节点 3.随机链表的复制 1.判断链表是否有环 这道题链表尾指针很有可能指向链表中任何一个节点,所以是带环的意思,当然尾指针很有可能指向他自己 所以我们分析一下,该怎么判断带有环,有些人直接说我就判断是否和我原来的值相等,相等的话就是代表有环,但这种情况不能确保一定有环,因为即使我没进环也有可能值相等,所以这个行不通,所以我们要判断的话还得需要快慢指针,若快指针追上慢指针代表这链表有环,为什么快指针追上慢指针就会带有环那? 我们来画图分析一下 slow和fast最初都在头结点, 我们让fast一次走两步,slow一次走一步,假如没换那么fast或fast->next就会指向空,假如有环,那么fast先进环,slow后进环,若fast追上slow就证明了这个链表就带有环 代码如下 这道题曾经被一个面试官提出新的问题 为什么一定会相遇,有没有可能会错过,永远追不上? 我们先来看第一个问题,我们假设slow进环后与fast距离为N, 环的长度是C 那么fast追击slow的过程距离变化如下: N为偶数 N为奇数 N N N-2 N-2 N-4 N-4 …… …… 4 3 2 1 0 -1 可以看出N若为偶数追上了,若N为奇数,则代表fast错过了,需要新的一轮追击,此刻他们之间的距离就变成了C-1,继续追击,我们根据第一轮追击可以得知,C-1是偶数的话代表第二轮追上了,C-1还是奇数的话,又错了一位,距离又变成了C-1,C-1既然是奇数,那就代表永远追不上了 所以追不上的条件前提是,第二轮的C-1是奇数,第一轮的N是奇数,但我们想想这两个条件会不会同时存在 这里我们就需要用到数学列等式的思维来判断两个条件是否可以同时存在 我们假设进环之前的距离是L 那么slow刚进环时,slow走过的距离是L,此刻我们假设fast走了x圈,那fast走过的距离就是L+x*C+C-N fast的距离是slow的三倍 那么就有了等式 3L=L+x*C+C-N 换算为:2*L=(x+1)*C-N 偶数=(x+1)*偶数-奇数 我们根据数学运算法则中 ,N是奇数时,C必须是奇数,才能使等式成立,N是偶数时,C必须也是偶数,才能使等式成立。 所以,当N是奇数时,C为奇数,C-1为偶数,所以C-1不可能为奇数,所以不可能永远追不上,肯定相遇。 结论:一定能追上 N是偶数第一轮就追上了 N是奇数第一轮追不上,第二轮就追上了 2.返回入环的第一个节点 上面那道题是判断是否有环,这道题就是若有环,返回环的第一个节点,所以我们还是需要用到快慢指针,我们画图表示 如图,这里其实有个非常巧妙的方法,我们让慢指针一次走一步,快指针一次走两步,直到环里相遇,再创建两个指针,一个从头开始走,另一个从快慢指针相遇的地方开始走,俩指针一次走一步,这俩指针若相遇,则相遇的点必定是进环的首节点 代码如下 可是为什么那? 我们还是用数学的方法来证明一下 我们假设,环之前的距离是L,环的长度为C,相遇点与入环点的距离为N,在慢指针进入环点时,快指针走了x圈 那么相遇时,slow走的距离是L+N fast走的距离是L+x*C+N fast走的路程是slow两倍 那么就有了等式 2*(L+N)=L+x*C+N

数据结构的队列(c语言版)

一.队列的概念 1.队列的定义 队列是一种常见的数据结构,它遵循先进先出的原则。类似于现实生活中排队的场景,最先进入队列的元素首先被处理,而最后进入队列的元素则要等到前面的元素都被处理完后才能被处理。 在队列中,元素只能从一端插入,称为队尾,而只能从另一端删除,称为队头。新的元素被插入到队尾,而最早插入的元素位于队头。这样,当一个元素被处理或删除时,它前面的元素就会成为新的队头。 2.队列的应用 队列的应用: 1.任务调度:多个任务按照顺序排队等待执行。 2.广度优先搜索(BFS):在图或树的遍历中,按层次遍历节点。 3.缓存管理:缓存中的数据按照访问顺序排列,最先进入的数据最先被替换。 4.算法设计:某些算法的设计与队列密切相关,如哈夫曼编码、循环队列等。 3.队列的优缺点 优点: 先进先出(FIFO):队列保持元素的插入顺序,最先插入的元素最先被处理,符合很多实际问题的需求。简单高效:队列的基本操作入队和出队的时间复杂度为O(1),无论队列的大小如何,操作的时间复杂度都是固定的。应用广泛:队列在很多算法和应用中有广泛的应用,如任务调度、广度优先搜索、缓存管理等。 缺点: 随机访问困难:队列只允许在队头删除元素,而在队尾插入元素,不支持随机访问。如果需要在其他位置插入或删除元素,操作效率较低。队列大小限制:使用数组实现的队列在创建时需要指定最大容量,因此队列的大小有限。如果队列已满,则无法再插入新的元素。存储空间浪费:如果队列的实际元素数量远小于最大容量,那么可能会造成存储空间的浪费,因为队列的容量是固定的。 二.队列的功能 队列常见的功能: 入队:将一个元素插入到队列的尾部,成为新的队尾。出队:从队列的头部删除并返回一个元素,将队列的头部指针向后移动一位。获取队头元素:返回队列的头部元素,但不删除它。检查队列是否为空:检查队列中是否没有元素,即队列是否为空。检查队列是否已满:检查队列是否已达到其最大容量,无法再插入新的元素。清空队列:将队列中的所有元素删除,使其变为空队列。获取队列中元素的数量:返回队列中元素的当前数量。遍历队列:从队列的头部开始遍历到尾部,依次访问每个元素。 三.队列的实现 1.定义队列结构 Queue 是一个结构体类型,包含以下成员: elements:类型为 int* 的指针,用于存储队列中的元素。通常情况下,可以通过动态内存分配来为该指针分配足够的内存空间,以存储队列的元素。front:整型变量,表示队列头部的索引。它指向队列中的第一个元素。rear:整型变量,表示队列尾部的索引。它指向队列中最后一个元素。maxSize:整型变量,表示队列的最大容量。它用于限制队列中元素的数量,防止队列溢出。 typedef struct { int* elements; // 存储元素的数组 int front; // 队列头部索引 int rear; // 队列尾部索引 int maxSize; // 队列的最大容量 } Queue; 2.初始化队列 initQueue(Queue* queue, int maxSize):初始化队列。该函数接受一个指向 Queue 结构的指针以及队列的最大容量 maxSize。在函数内部,它为队列的元素数组分配内存空间,并将队列的头部索引 front 设置为 0,尾部索引 rear 设置为 -1,表示队列为空。 // 初始化队列 void initQueue(Queue* queue, int maxSize) { queue->elements = (int*)malloc(sizeof(int) * maxSize); queue->front = 0; queue->rear = -1; queue->maxSize = maxSize; } 3.

视频生成Sora的全面解析:从AI绘画、ViT到ViViT、TECO、DiT、VDT、NaViT等

前言 真没想到,距离视频生成上一轮的集中爆发(详见《Sora之前的视频生成发展史:从Gen2、Emu Video到PixelDance、SVD、Pika 1.0》)才过去三个月,没想OpenAI一出手,该领域又直接变天了 自打2.16日OpenAI发布sora以来(其开发团队包括DALLE 3的4作Tim Brooks、DiT一作Bill Peebles、三代DALLE的核心作者之一Aditya Ramesh等13人),不但把同时段Google发布的Gemini 1.5干没了声音,而且网上各个渠道,大量新闻媒体、自媒体(含公号、微博、博客、视频)做了大量的解读,也引发了圈内外的大量关注 很多人因此认为,视频生成领域自此进入了大规模应用前夕,好比NLP领域中GPT3的发布一开始,我还自以为视频生成这玩意对于有场景的人,是重大利好,比如在影视行业的 对于没场景的人,只能当热闹看看,而且我司大模型项目开发团队去年年底还考虑过是否做视频生成的应用,但当时想了好久,没找到场景,做别的应用去了 可当我接连扒出sora相关的10多篇论文之后,觉得sora和此前发布的视频生成模型有了质的飞跃(不只是一个60s),而是再次印证了大力出奇迹,大模型似乎可以在力大砖飞的情况下开始理解物理世界了,使得我司大模型项目组也愿意重新考虑开发视频生成的相关应用 本文主要分为三个部分(初步理解只看第一部分即可,深入理解看第二/三部分,更多细节则看第四部分) 第一部分,侧重sora的核心技术解读 方便大家把握重点,且会比一切新闻稿都更准确,此外 如果之前没有了解过DDPM、ViT的,建议先阅读下此文《从VAE、VQ-VAE、扩散模型DDPM、DETR到ViT、Swin transformer》,特别是其中的VAE、DDPM,不然下文屡屡提到时,你可能会有所懵 如果之前没有了解过图像生成的,建议先阅读下此文《从CLIP、BLIP到DALLE、DALLE 2、DALLE 3、Stable Diffusion》第二/三部分,侧重sora相近技术的发展演变 把sora涉及到的关键技术在本文中全部全面、深入、细致的阐述清楚,毕竟如果人云亦云就不用我来写了 且看完这部分你会发现,从来没有任何一个火爆全球的产品是一蹴而就的,且基本都是各种创新技术的集大成者(Google很多工作把transformer等各路技术发扬光大,但OpenAI则把各路技术 整合到极致了..)第四部分,对sora的32个reference的总结分析 由于sora实在是太火了,网上各种解读非常多,有的很专业(比如互相认识十多年的张俊林老师对sora的解读,也是本文的重要参考之一),有的看上去一本正经 实则是胡说八道(即便他的title看起来有一定的水平),为方便大家辨别什么样的解读是不对的,特在此部分把一些sora官方博客上的32个reference做下总结分析 总之,看本文之前,如果你人云亦云的来一句:sora就是DiT架构,我表示理解。但看完全文后你会发现 如果只允许用10个字定义sora的模型结构,则可以是:潜在扩散架构下的Video Transformer如果允许25个字以内,则是:带文本条件融合且时空注意力并行计算的Video Diffusion Transformer 更多,则在该课里见:视频生成Sora的原理与复现 [全面解析且从零复现sora缩略版] 第一部分 OpenAI Sora的关键技术点 1.1 Sora的三大Transformer组件 1.1.1 从前置工作DALLE 2到sora的三大组件 为方便大家更好的理解sora背后的原理,我们先来快速回顾下AI绘画的原理(理解了AI绘画,也就理解了sora一半) 以DALLE 2为例,如下图所示(以下内容来自此文:从CLIP、BLIP到DALLE、DALLE 2、DALLE 3、Stable Diffusion) CLIP训练过程:学习文字与图片的对应关系 如上图所示,CLIP的输入是一对对配对好的的图片-文本对(根据对应文本一条狗,去匹配一条狗的图片),这些文本和图片分别通过Text Encoder和Image Encoder输出对应的特征,然后在这些输出的文字特征和图片特征上进行对比学习DALL·E2:prior + decoder 上面的CLIP训练好之后,就将其冻住了,不再参与任何训练和微调,DALL·E2训练时,输入也是文本-图像对,下面就是DALL·E2的两阶段训练: 阶段一 prior的训练:根据文本特征(即CLIP text encoder编码后得到的文本特征),预测图像特征(CLIP image encoder编码后得到的图片特征) 换言之,prior模型的输入就是上面CLIP编码的文本特征,然后利用文本特征预测图片特征(说明白点,即图中右侧下半部分预测的图片特征的ground truth,就是图中右侧上半部分经过CLIP编码的图片特征),就完成了prior的训练 推理时,文本还是通过CLIP text encoder得到文本特征,然后根据训练好的prior得到类似CLIP生成的图片特征,此时图片特征应该训练的非常好,不仅可以用来生成图像,而且和文本联系的非常紧(包含丰富的语义信息) 阶段二 decoder生成图:常规的扩散模型解码器,解码生成图像 这里的decoder就是升级版的GLIDE(GLIDE基于扩散模型),所以说DALL·E2 = CLIP + GLIDE 所以对于DALLE 2来说,正因为经过了大量上面这种训练,所以便可以根据人类给定的prompt画出人类预期的画作,说白了,可以根据text预测画作长什么样

C——双向链表

一.链表的概念及结构 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。什么意思呢?意思就是链表在物理结构上不一定是连续的,但在逻辑结构上一定是连续的。链表是由一个一个的节点连接而成的。 我们借助这个图来理解链表的物理结构上的不连续和逻辑结构上的连续。这上面的6个节点在内存空间的地址不是连续的,但是他们在逻辑上却是连续的,1->2->3->4->5->6。 与链表相似的还有顺序表,顺序表与链表相同都是线性表的一种。而顺序表的底层其实就是数组,所以顺序表在物理结构上是连续的,在逻辑结构上也是连续的。 二.链表的分类 我们从上图可以得知,链表一共有2*2*2种。 分别为: 单向带头循环链表、单向带头不循环链表、单向不带头循环链表、单向不带头不循环链表、双向带头循环链表、双向带头不循环链表、双向不带头循环链表、双向不带头不循环链表。 而在这么多种的链表中,最常用的只有单向不带头不循环链表(也称单链表),以及双向带头循环链表(也称双向链表)。我们今天来了解这两种之一的双向链表。 三.双向链表的结构 双向链表全称为:双向带头循环链表。怎么理解这里面的每一个修饰词呢?我们先来看一下双向链表的结构。 四.实现双向链表 我们在实现双向链表的时候可以将所有的链表所需的函数的声明都放到一个List.h中,将函数的定义放到一个List.c中,我们还需要一个test.c用来测试我们的双向链表中的方法。 4.1链表的元素——节点的创建 节点是链表的组成元素,而对于双向链表来说,每一个节点不仅要存储数据还要存储前一个节点的地址和后一个节点的地址,没有哪一种内置类型可以同时包含这三种,所以我们节点的创建要用到自定义类型——结构体。 struct ListNode { int val; struct ListNode* prev; struct ListNode* next; }; 这样的结构体就可以表示一个节点了嘛?难道我们的节点只能存储整型嘛?当然不是,我们的节点可以存储任意数据,但是我们如果直接这样写的话,等到代码量大了,如果我们想要该链表存储字符型,我们到时候要修改的地方非常多。所以我们有一个一劳永逸的方法: typedef int ListValType; 我们可以给int类型利用typedef关键字起一个新名字ListValType,我们结构体内部定义 int类型的成员时不再使用int a;而使用ListValType a;这两种的效果是一样的。以后我们想修改链表存储数据的类型的时候只需要将最前面的重命名语句中的int类型改为其他类型即可。 我们在创建节点的时候要写struct ListNode这么长一串,我们也可以利用typedef关键字给该结构体类型起一个新名字,避免了结构体名太长的问题。 所以我们节点的定义最终为: typedef int ListValType; typedef struct ListNode { ListValType val; struct ListNode* prev; struct ListNode* next; }ListNode; 4.2双向链表的初始化 双向链表是带头链表,而这个头就是头节点(哨兵位)。所以双向链表的初始化其实就是创建一个头节点。头节点也是节点,所以双向链表的初始化其实就是创建一个节点,只不过这个节点没有有效的值。 //创建节点 ListNode* Buynode(ListValType x) { ListNode* node = (ListNode*)malloc(sizeof(ListNode)); if (node == NULL) { perror("

【Java】JDK1.8 HashMap源码,put源码详细讲解

📝个人主页:哈__ 期待您的关注 目录 一、HashMap中的变量 1.默认容量 2.最大容量 3.负载因子 4.列表树化的阈值 5.红黑树转列表的阈值 6.树化时的最小数组容量 7.元素数组(存放我们插入的数据) 8.数组的大小(并非容量,而是实际放了多少个数据结点到table数组中) 9.Node结点 10.扩容阈值 二、HashMap的put方法 三、resize方法 在Java中,HashMap结构是被经常使用的,在面试当中也是经常会被问到的。这篇文章我给大家分享一下我对于HashMap结构源码的理解。 HashMap的存储与一般的数组不同,HashMap的每一个元素存储的并不是一个值,而是一个引用类型的Node结点,这也就意味着这个Node结点有被扩充的可能,因为这个Node结点可以是一个链表的Head结点,也可以是一棵树的根节点。 HashMap的存储数组叫做table,也可以称作“桶”,试想这样的一个场景:我们在一排放了3个桶,同时我们有4个苹果,如果我们要把所有的苹果放到桶当中,那么必然有一个桶中 的苹果个数>=2。 这种情况在我们的HashMap中也会出现,我们的HashMap结构是把很多的数据存放到一个容量达不到元素个数的数组当中,就如同桶和苹果一样。 因此我们的HashMap结果会出现上图所示的一种冲突,我们成为散列冲突,也叫做Hash冲突 。 出现冲突不要怕,解决冲突就是了,我们的一个桶当中可以放两个苹果,自然HashMap的table数组的一个位置也可以存放两个元素。 问题来了,我们现在假设有16个桶,同时间断性的向桶中放苹果,而且还要能够方便我们后续去拿苹果和寻找苹果,那我们这16个桶还够用吗?我们这样子直接把苹果放进桶里,还能够方便我们后续找苹果吗? 行了,解决吧,现在假设你是一位苹果管理员,你该怎么优化一下?你看看这样子行不行,不就是放苹果、找苹果嘛,既然让我来管理,那我希望把苹果平均放到桶当中,每次我放的位置尽量不要和之前的苹果放的位置有冲突,如果桶多的话,你也不能一个一个桶去看吧,所以,我们定义了一个算法,我根据这个苹果的生产ID序列号去寻找对应的桶放进去,如同取余放置一样。这是个不错的思路。但序列号都是有规律的,这样会影响我们的放置,我们希望是一个很随机的结果,因此我们给这个序列号随机变动几个位置后在选择桶。在HashMap中,这样的序列号叫做hashCode值,经过一个扰动函数后,我们的到的扰动的值叫做hash。 如何存放的问题解决了,但苹果一旦多了还是会产生冲突,一个桶里放8个我还能找得到,但是一个桶里放20个,30个苹果,那我就找不到那个序列号的苹果了。 二叉树我们都学过,倘若我们把桶内的苹果以二叉树的方式进行存储,那这样我们在查找的时候是不是就省了很多时间呢?因此HashMap中的table内的一个元素列表长度>8的时候,进行树化操作。但也不是非要进行树化的,毕竟树化也要浪费很多资源。当我们的桶的数量<=64的时候,我们不进行树化操作,我们进行数组扩容,把table扩大2倍,这样的话,我们在放苹果的时候发生冲突的概率就会降低。但如果容量已经达到了64,我们就考虑把链表转为红黑树(也是二叉树)了。 以上的过程不知道你是否理解了没,放苹果的案例和HashMap存储元素的过程相似,现在我们来看代码吧。 一、HashMap中的变量 1.默认容量 HashMap无参构造方法调用时,我们的HashMap数组的初始容量是16。 /** * 默认初始化的容量大小,且必须是2的整数倍 */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 2.最大容量 记录了我们HashMap所能存储的最大的元素个数。 /** * 我们的元素数组的最大的容量,如果我们设定的最大容量比这个数还大 * 那我们就把容量设定为这个最大的值 */ static final int MAXIMUM_CAPACITY = 1 << 30; 3.负载因子 负载因子决定了HashMap在存储更多数据时如何扩展其容量。默认情况下,当负载因子达到0.75时,HashMap会进行扩容。这意味着,当HashMap中的元素数量达到数组容量的0.75倍时,数组的大小就会翻倍,以便容纳更多的数据。 为什么选择0.75作为默认的负载因子呢?这并不是随意的选择,而是经过深思熟虑后的优化值。负载因子实际上是一个权衡空间和时间的参数。在理想情况下,如果负载因子为1,这意味着每个索引位置上都有一个键值对存在。然而,当两个或更多的键具有相同的哈希值时,就会发生冲突,这会导致查询效率降低。因此,通过设置一个适当的负载因子,可以平衡键值对的存储效率和查询效率。 通过将负载因子设置为0.75,可以在空间和时间效率之间取得平衡。这意味着,当数组接近其容量时,HashMap会进行扩容,以避免因哈希冲突而导致的性能下降。同时,这个值也避免了因频繁扩容而产生的额外开销。在大多数情况下,0.75的负载因子可以提供较好的性能。 /** * 如果我们并没有自己初始化一个平衡因子,这个就是默认的平衡因子 */ static final float DEFAULT_LOAD_FACTOR = 0.

【数据结构-之八大排序(下),冒泡排序,快速排序,挖坑法,归并排序】

🌈个人主页:努力学编程’ ⛅个人推荐:基于java提供的ArrayList实现的扑克牌游戏 |C贪吃蛇详解 ⚡学好数据结构,刷题刻不容缓:点击一起刷题 🌙心灵鸡汤:总有人要赢,为什么不能是我呢 hello,这里提前祝大家五一快乐,每天都能快快乐乐,并且每天都能学到东西。 我们今天继续顺着上次没有说完的排序算法,这里简单复习一下,我们根据每种排序的方式不同,大致上将常见的排序算法分为选择排序,插入排序,交换排序,归并排序。今天就大家学习我们剩下的两个大类,交换排序和归并排序。 🌈交换排序 ⚡冒泡排序 冒泡排序算法的原理如下: 1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。 2.对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。 3.针对所有的元素重复以上的步骤,除了最后一个。 4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 这里也给大家一个动图,帮助大家理解: public static void bubbleSort(int[] array) { for (int i = 0; i < array.length-1; i++) { boolean flg = false; for (int j = 0; j < array.length-1-i; j++) { if(array[j] > array[j+1]) { swap(array,j,j+1); flg = true; } } //时间复杂度为:O(N) if(!flg) { break; } } } 总体来说呢,冒泡排序是这几种排序中最简单的一种排序,容易理解,代码的逻辑也没有那么复杂,唯一需要提醒大家的,就是两个for循环里面的循环结束条件的判断,这里需要着重强调!!! 1. 冒泡排序是一种非常容易理解的排序 2. 时间复杂度:O(N^2) 3. 空间复杂度:O(1)

【c++】模板编程解密:C++中的特化、实例化和分离编译

🔥个人主页:Quitecoder 🔥专栏:c++笔记仓 朋友们大家好,本篇文章我们来学习模版的进阶部分 目录 `1.非类型模版参数``按需实例化` `2.模版的特化``函数模版特化``函数模版的特化``类模版``全特化``偏特化` `3.分离编译``模版分离编译` 1.非类型模版参数 模板参数分类类型形参与非类型形参。 类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用 非类型模板参数允许你将一个值(而不是一个类型)直接传递给一个模板。非类型模板参数可以是一个整型值、一个指针或者一个引用,因为这些参数不是类型,所以被称为“非类型模板参数”。 非类型模板参数可以让你根据这些值创建模板实例。例如,你可以根据整型非类型模板参数定义编译时决定大小的数组 引入下面的例子: #define N 10 template<class T> class array { public: T& operator[](size_t index) { return _array[index]; } const T& operator[](size_t index)const { return _array[index]; } size_t size()const { return _size; } bool empty()const { return 0 == _size; } private: T _array[N]; size_t _size; }; 对于这个静态数组,我们只能用宏定义来确定数组的大小,那如果我一次性想要开两个大小不同的数组呢? array<int> a1;//大小为10 array<int> a2;//大小为100 这里就需要非类型模版参数 template<class T, size_t N = 10> class array { public: T& operator[](size_t index) { return _array[index]; } const T& operator[](size_t index)const { return _array[index]; } size_t size()const { return _size; } bool empty()const { return 0 == _size; } private: T _array[N]; size_t _size; }; 在这个例子中,N 就是一个非类型模板参数,它表示数组的大小,而 T 是一个类型模板参数代表数组中元素的类型