目录
🌈 前言🌈
📁 unordered系列关联式容器
📁 底层结构
📂 哈希概念
📂 哈希冲突
📂 哈希函数
📂 哈希冲突解决
📁 模拟实现
📁 总结
🌈 前言🌈 欢迎收看本期【C++杂货铺】,本期内容将讲解C++的STL中的unordered系列容器,其中包含了unordered_map 和 unordered_set 的使用,底层结构哈希的原理,实现,最后模拟实现unordered系列的容器。
📁 unordered系列关联式容器 在C++98中,STL提供了底层为红黑树结构的系列关联式容器,在查询时效率可达到 O(log2),即最差情况下需要比较红黑树的高度次,当书中的节点比较多时,查询效率也不理想。
最好的查询是,进行很少的比较次数就能将元素找到,因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是底层结构不同,本文中只对unordered_map 和 unordered_set进行介绍。
其中,unordered_map是存储 <key , value>键值对的关联式容器,其允许通过key快速的索引找到对应的value。
📁 底层结构 unordered系列的关联式容器效率之所以比较高,是因为底层使用了哈希结构。
📂 哈希概念 顺序结构及平衡树中,元素关键码与其存储位置之间没有对应关系,因此在查找一个元素时,必须要经过关键码的多次比较。顺序查找时间复杂度为O(N) ,平衡术中为树的高度,即O(logN),搜索效率取决于搜索过程中元素的比较次数。
理想的搜索方法是:可以不经过任何比较,一次直接从表中得到搜索的元素。如果构造一种存储结构,通过某种函数(HashFunc)使得元素的存储位置和它的关键码之间能够建立一种映射关系,那么在查找时通过该函数可以很快找到该元素。
该结构中:
● 插入元素:根据插入元素的关键码,用哈希函数计算出该元素的存储位置并按次位置进行存放。
● 搜搜元素:对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按次位置取元素的比较,若关键码相等,则搜索成功。
该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出的结构为哈希表(散列表)。
该方法不必经过多次关键码的比较,因此搜索的速度比较快。
📂 哈希冲突 当两个数据元素的关键码 i != j , 但是Hash(i) == Hash(j),即:不同关键码通过相同的哈希函数计算出相同的哈希地址,这种现象成为哈希冲突(哈希碰撞)。
📂 哈希函数 引起哈希冲突的一个原因可能是,哈希函数设计不合理。
哈希函数的设计原则: 1. 哈希函数的定义域必须包括需要存储的全部关键码,如果散列表允许有m个地址,其值域必须在0 ~ m-1 之间。
前言
上篇博客我们说了有关二叉树顺序结构——堆,堆是完全二叉树,但我们对于普通的二叉树(不一定为完全二叉树),我们该用什么结构实现那,本篇就来详细说一下,二叉树另一个实现的结构,链式结构
💓 个人主页:小张同学zkf
⏩ 文章专栏:数据结构
若有问题 评论区见📝
🎉欢迎大家点赞👍收藏⭐文章
目录
1.二叉树的创建与遍历
1.1 前序,中序,后序遍历
1.2层序遍历 1.3二叉树的创建
2.二叉树的节点个数
3.二叉树的叶子结点个数
4.二叉树的深度
5.寻找x节点
6.判断是否为完全二叉树
7.销毁二叉树
8.以下是二叉树的实现
1.二叉树的创建与遍历 1.1 前序,中序,后序遍历 看这个题之前,我们先来说一下三个遍历
学习二叉树结构,最简单的方式就是遍历。所谓 二叉树遍历 (Traversal) 是按照某种特定的规则,依次对二叉 树中的结点进行相应的操作,并且每个结点只操作一次 。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础 按照规则,二叉树的遍历有: 前序 / 中序 / 后序的递归结构遍历 : 1. 前序遍历 (Preorder Traversal 亦称先序遍历 )—— 访问根结点的操作发生在遍历其左右子树之前。 2. 中序遍历 (Inorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之中(间)。 3. 后序遍历 (Postorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之后。 由于被访问的结点必是某子树的根, 所以 N(Node )、 L(Left subtree )和 R(Right subtree )又可解释为 根、根的左子树和根的右子树 。 NLR 、 LNR 和 LRN 分别又称为先根遍历、中根遍历和后根遍历。 前序遍历递归图解 : 对上图,遍历结果如下 前序遍历结果: 1 2 3 4 5 6 中序遍历结果: 3 2 1 5 4 6 后序遍历结果: 3 2 5 6 4 1 那了解了三个遍历,那对应的代码如何实现那?
Spring到底是如何来实现IOC和DI的,那接下来就通过一些简单的入门案例,来演示下具体实现过程。
目录
前期准备
一、IOC入门案例
思路分析
代码实现
二、DI入门案例
思路分析
代码实现
总结
前期准备 使用IDEA创建Maven项目,首先需要配置好Maven,新建一个Maven项目。
一、IOC入门案例 思路分析 (1)Spring是使用容器来管理bean对象的,那么管什么?
主要管理项目中所使用到的类对象,比如(Service和Dao) (2)如何将被管理的对象告知IOC容器?
使用配置文件
(3)被管理的对象交给IOC容器,要想从容器中获取对象,就先得思考如何获取到IOC容器?
Spring框架提供相应的接口
(4)IOC容器得到后,如何从容器中获取bean?
调用Spring框架提供对应接口中的方法
(5)使用Spring导入哪些坐标?
用别人的东西,就需要在pom.xml添加对应的依赖
代码实现 (1)创建Maven项目,在pom.xml 添加Spring的依赖jar包,
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> (2)创建BookService,BookServiceImpl,BookDao和BookDaoImpl四个类,
目录如下:
package com.water.dao; public interface BookDao { public void save(); } package com.water.dao.impl; import com.water.dao.BookDao; public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save .
全开源运营版本聊天室H5实时聊天室群聊聊天室自动分配账户完群组/私聊/禁言等功能
都是去年买的,很多买的源码基本都下架了,详情还是套已经老站的,可能网上已经流传了点,不过还是不影响这个源码的牛逼所在
运营版本的聊天室,可以添加好友,建立群组,私聊,禁言功能
H5+TP5.0+mysql+PHP 源码开源不加密
本源码下载地址: Thinkphp聊天室H5实时聊天室群聊聊天室自动分配账户完群组/私聊/禁言等功能/全开源运营版本 - 521源码
更多网站源码,游戏源码,学习教程,请点击👉-521源码-👈获取最新资源
目录
一.JVM是什么
二.JVM 运行的基本流程
三.JVM 运行时数据区
1.程序计数器(Program Counter Register)
2.堆(Heap)
3.Java虚拟机栈(JVM Stack)
4.本地方法栈(Native Method Stack)
5.方法区(Method Area)
6.运行时常量池(Runtime Constant Pool):
四.JVM 类加载
双亲委派模型
五.垃圾回收
1.死亡对象的判断算法
2.垃圾回收算法
一.JVM是什么 JVM(Java Virtual Machine)是Java虚拟机的缩写,它是Java编程语言的关键部分之一。JVM是一个虚拟的计算机,它是在物理计算机上模拟的计算机,用于执行Java字节码指令。
当你编写Java程序时,Java源代码首先被编译成字节码(.class文件),然后由JVM解释和执行这些字节码指令。JVM负责管理内存、执行垃圾回收、加载类、执行字节码等任务,从而实现Java程序的跨平台特性。
JVM的存在使得Java程序具有跨平台性,即你编写的Java程序可以在任何安装了JVM的操作系统上运行,而不需要对程序进行重新编译。这种特性极大地简化了Java程序的开发和部署过程。
二.JVM 运行的基本流程 1. 编写:Java源代码开发者使用Java语言编写源代码,保存为.java文件。
2. 编译源代码:使用Java编译器(如javac)将.java文件编译成Java字节码,存储在.class文件中。字节码是一种中间代码,它与具体的硬件和操作系统无关。
3. 类加载:当Java程序运行时,JVM通过类加载器(Class Loader)加载这些.class文件。类加载器按照以下步骤执行:
加载:读取硬盘上的.class文件,将数据转化为方法区内的数据结构。链接:验证加载的类信息,准备并解析符号引用到直接引用。初始化:对类变量进行初始化,执行静态代码块。 4. 执行:类加载完成后,JVM将字节码提交给执行引擎。执行引擎可以通过解释器逐条解释执行字节码,也可以通过即时编译器(JIT)将部分字节码转换成本地机器码以提高效率。
5. 运行时数据区域:JVM在运行过程中,会使用到以下几个主要的内存区域:
程序计数器:每个线程有一个程序计数器,是线程私有的。Java栈:每个线程运行时都会创建一个Java栈,用于存放帧。本地方法栈:为执行本地方法服务。堆:几乎所有的对象实例都在这里分配内存。方法区:用于存储已被虚拟机加载的类信息、常量、静态变量等信息。 6. 垃圾回收:JVM在堆内存中管理应用程序创建的所有对象实例。当对象不再被引用时,垃圾回收器将清理这些对象占用的内存,以确保内存的有效利用。
7. 退出:程序执行完毕后,或者遇到未捕获的异常或错误导致退出,JVM将终止程序并释放所有资源。
三.JVM 运行时数据区 当JVM 把字节码(class文件)通过类加载器(ClassLoader)加载时,文件会被加载到内存中的运行时数据区(Runtime Data Area)
JVM的运行时数据区包括以下几个主要的部分:
1.程序计数器(Program Counter Register) 程序计数器是一个非常关键的组件,主要用来存储当前线程执行的字节码的行号指示器。以下是程序计数器的几个主要特点:
线程私有性:程序计数器是线程私有的,这意味着每个线程都有自己独立的程序计数器,线程之间的计数器互不影响。这种设计是为了线程切换后能恢复到正确的执行位置。
执行追踪:程序计数器的主要功能是指示线程当前正在执行的Java字节码的具体位置。如果执行的是Java方法,程序计数器记录的是正在执行的字节码指令的地址;如果执行的是Native方法,则程序计数器的值为空(Undefined)。
内存需求小:由于程序计数器仅仅存储线程执行的代码位置,它的内存需求通常比较小。
垃圾回收无关:程序计数器是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。也就是说,它对垃圾回收过程没有直接影响。
程序计数器的存在使得Java虚拟机可以支持多线程环境中的线程切换,而不会发生执行状态混乱的问题。这也是Java虚拟机能够支持同时执行多段代码逻辑的关键技术之一。在Java多线程编程中,程序计数器为每个线程的独立运行提供了保障,确保了程序执行的正确性和效率。
2.堆(Heap) 堆(Heap)是Java虚拟机中最大的一块内存区域,用于存储对象实例和数组。堆是所有线程共享的,而且在Java虚拟机启动时就会被创建。以下是堆的一些主要特点和作用:
目录 1 什么是层序遍历2 二叉树层序遍历的基本思路3 二叉树层序遍历的实现 1 什么是层序遍历 我们从字面意思就明白,所谓层序,就是一层一层按顺序去遍历一个二叉树,这和我们之前了解的按前中后序遍历方式完全不同 比方说这颗二叉树:
前序遍历:
层序遍历:
2 二叉树层序遍历的基本思路 我们引入一个队列,入这棵树的根进队列,只要这个树的非叶子节点出队列了,立马让这个节点的子节点如队列,如此循环,我们直接看动画 3 二叉树层序遍历的实现 //层序遍历 void TreeLevelOrder(BTNode* proot) { QU qu; // 创建队列 QInit(&qu); // 队列初始化 if (proot == NULL) // 判空 { return; } else { QPush(&qu, proot); // 二叉树不是空就先把第一个值入队 } while (!QEmpty(&qu)) // 只要队列不是空就一直循环,直到队列为空 { QDataType tmp = QFront(&qu); // 取队头 QPop(&qu); // 队头元素出队 if (tmp->leftnode != NULL) // 取队头的子节点入队(除非子节点为空) { QPush(&qu, tmp->leftnode); } if (tmp->rightnode !
🌈 个人主页:danci_
🔥 系列专栏:《设计模式》《MYSQL应用》
💪🏻 制定明确可量化的目标,坚持默默的做事。
✨欢迎加入探索MYSQL慢查询之旅✨
👋 大家好!我是你们的技术达人danci_btq。你是否因为MYSQL慢查询而头疼不已?今天我来教你如何高效地优化这些慢查询,让你的数据库飞速跑!🚀 在本文中,我们将探索一些简单而有效的方法,让你轻松应对MYSQL慢查询问题。准备好了吗?Let’s go!💪
文章目录 Part1、认识MYSQL慢查询 🐢Part2、配置和识别慢查询 🚀Part3、分析慢查询原因 🎭Part4、解决和避免慢查询总结 💖 Part1、认识MYSQL慢查询 🐢 在MySQL数据库中,慢查询(Slow Query)通常指的是执行时间超过预设阈值的查询语句。这些查询可能会消耗大量的数据库资源,导致系统性能下降或响应时间延长。因此,监控和优化慢查询是数据库管理员(DBA)和开发人员的重要任务之一。
慢查询的影响
性能瓶颈:慢查询会消耗大量的CPU、内存和I/O资源,导致数据库性能下降。响应时间:用户请求的响应时间可能会因为慢查询而延长,影响用户体验。资源浪费:不必要的慢查询会浪费数据库服务器的资源,降低整体系统的稳定性。 Part2、配置和识别慢查询 🚀 开启慢查询监控 mysql有一个配置是long_query_time,值是数字,单位是秒。当一条SQL语句执行耗时超过long_query_time的值时,mysql就认为这条sql为慢查询SQL。
临时配置
找开命令窗口配置
// 查看慢查询是否开启 show variables like 'slow_query_log'; // 开启慢查询(值可以是1或on) set global slow_query_log = 1; // 关闭慢查询(值可以是1或off) set global slow_query_log = 0; // 查看long_query_time值 show variable like 'long_query_time'; // 设置long_query_time值 (单位是秒) set global long_query_time=5; 永久生效配置
MySQL的配置文件(通常是 my.cnf 或 my.ini)
如果你还没有启用慢查询日志,你还需要在配置文件中设置 slow_query_log 为 ON,并指定一个日志文件路径(如果需要的话)。
本篇主要介绍SQL优化的相关内容。
目录
一、数据插入
批量插入多行
通过事务插入
Load指令
二、主键优化
页分裂
页合并
三、order by优化
四、gruop by优化
五、limit优化
六、count优化
七、update优化
对于每一次来自客户端的请求,我们通常都需要访问一次数据库,而访问数据库又是比较耗时的,因此我们如果能够掌握一定的SQL优化的技巧并熟练运用的话,就能大大缩减一条请求的响应时间,下面让我们来了解一下常见的SQL优化技巧。
一、数据插入 我们在执行插入操作时,需要进行一次磁盘IO将数据插到磁盘的相应位置,如果只插入一行记录还好,但如果要插入很多行数据呢?这意味着需要进行很多次磁盘IO,从而消耗大量的时间,这显然是不科学的。下面我们来了解三种更为高效的多行数据插入的方式。
批量插入多行 我们可以在一次insertSQL中批量插入多行数据,语法如下:
insert into 表名 values(数据),(数据),(数据);
这样我们只需要一次磁盘IO就能完成多行数据的插入。
通过事务插入 我们可以开启一个事务来进行多行数据的插入操作,这样只要将事务提交一次,就能完成批量数据行的插入。
start transcation;
insert语句
.....
commit;
Load指令 如果插入的数据量高达几百万行,显然前面两种方式也是不合适的,因此,我们需要通过Load指令来完成这种百万级的数据插入。
首先,我们首先要准备一个文件,里面包含要插入的数据 然后检查MySQL是否有开启 从本地文件中读取数据,具体为查看local _ infile参数的值,
值为1为开启,为0则为关闭,如果关闭可以通过set或者修改配置文件来开启。
开启之后,我们就可以通过load指令来完成百万级插入了,语法如下:
load data local infile '文件路径’ into table 表名 fileds terminated by '文件中每个字段之间的分割符' lines terminated by '行分割符';
二、主键优化 在前面我们介绍索引的时候,主键索引的叶子节点里包含了整个行数据,而行数据又是包含在页逻辑结构中,而一个页的大小又是固定的16k,因此,一个页中能够存储的行数据是有限的,因此,如果主键是按乱序的数据进行插入的话,就有可能会出现页分类的现象,具体如下:
页分裂 首先我们来看一下主键顺序插入的情况:
主键顺序插入时,会先把一个页的空间放满,然后再放到另一个页中,这些页之间用指针连接
此时如果再插入一个主键值为13的数据,直接将数据放到主键为11的数据行后面即可。
如果是乱序插入会是什么情况呢?
我们在上图数据的基础上,再插入一个6,此时为了保证顺序,就需要把6插入到5的后面,但5后面已经有数据7了,因此无法进行插入此时,就会触发页分裂,page1会以5和7之间的间隙进行分裂,将分裂后半部分的数据放到一个新页中,然后将6插到5的后面,最后重新调整这几个页的顺序
从图中可以看出来,页分裂会导致页空间更加零散,从而降低了空间利用率,并且页分裂相对来说会比较耗时 。
相对页分裂还有页合并的情况,具体如下:
一、SparkSQL 概述 1. 概念 Spark SQL 是 Spark 用于结构化数据 (structured data) 处理的 Spark 模块,使用 SQL 的方式简化 RDD 的开发
2. Hive VS SparkSQL Hive 是早期唯一运行在 Hadoop 上的 SQL-on-Hadoop 工具,但是 MapReduce 计算过程中大量的中间磁盘落地过程消耗了大量的 I/O,降低的运行效率Shark 是为了提高 SQL-on-Hadoop的效率而产生的 SQL-on-Hadoop 工具,是基于 Hive 所开发的,它修
改了 Hive 中的内存管理、物理计划和执行三个模块,并使之能运行在 Spark 引擎上由于 Shark 对于 Hive 存在太多依赖(如采用 Hive 的语法解析器、查询优化器等等),制约了其发展,SparkSQL 由此应运而生,它抛弃了原有 Shark 的代码,但汲取了 Shark 的一些优点,如内存列存储(In-Memory Columnar Storage)、 Hive 兼容性等 数据兼容方面 SparkSQL 不但兼容 Hive,还可以从 RDD、parquet 文件、JSON 文件中获取数据,未来版本甚至支持获取 RDBMS 数据以及 cassandra 等 NOSQL 数据性能优化方面 除了采取 In-Memory Columnar Storage、byte-code generation 等优化技术外、将会引进 Cost Model 对查询进行动态评估、获取最佳物理计划等等组件扩展方面 无论是 SQL 的语法解析器、分析器还是优化器都可以重新定义,进行扩展 Shark 停止开发后,发展出了两个支线,其中 SparkSQL 作为 Spark 生态的一员继续发展,而不再受限于 Hive,只是兼容 Hive;而 Hive on Spark 是一个 Hive 的发展计划,该计划将 Spark 作为 Hive 的底层引擎之一,由此 Hive 将不再受限于一个引擎,可以采用 Map-Reduce、Tez、Spark 等引擎 3.
一、上传说明 文件上传花样百出,根据不同场景使用不同方案进行实现尤为必要。通常开发过程中,文件较小,直接将文件转化为字节流上传到服务器,但是文件较大时,用普通的方法上传,显然效果不是很好,当文件上传一半中断再次上传时,发现需要重新开始,这种体验不是很爽,下面介绍几种好一点儿的上传方式。
这里讲讲如何在Spring boot 编写上传代码,如有问题可以在下留言,我并在文章末尾附上Java上传源码供大家下载。
分片上传 分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分
隔成多个数据块(我们称之为Part)来进行分别上传,上传完之后再
由服务端对所有上传的文件进行汇总整合成原始的文件。
断点续传 断点续传是在下载/上传时,将下载/上传任务(一个文件或一个压缩
包)人为的划分为几个部分,每一个部分采用一个线程进行上传/下载,
如果碰到网络故障,可以从已经上传/下载的部分开始继续上传/下载
未完成的部分,而没有必要从头开始上传/下载。
二、Redis启动安装 Redis安装包分为 Windows 版和 Linux 版:
Windows版下载地址:https://github.com/microsoftarchive/redis/releases
Linux版下载地址: https://download.redis.io/releases/
我当前使用的Windows版本:
三、minio下载启动 windows版本可以参考我之前的文档:window10安装minio_minio windows安装-CSDN博客
启动会提示:
以上是密码设置问题需要修改如下:
set MINIO_ROOT_USER=admin
set MINIO_ROOT_PASSWORD=12345678
启动成功后会输出相应地址
四、上传后端Java代码 后端采用Spring boot项目结构,主要代码如下:
/** * 单文件上传 * 直接将传入的文件通过io流形式直接写入(服务器)指定路径下 * * @param file 上传的文件 * @return */ @Override public ResultEntity<Boolean> singleFileUpload(MultipartFile file) { //实际情况下,这些路径都应该是服务器上面存储文件的路径 String filePath = System.getProperty("user.dir") + "\\file\\"; File dir = new File(filePath); if (!
堆排序,无疑与堆这种数据结构有关。在了解堆排序之前,我们需要先了解堆的建立与维护方法。
堆 堆(二插堆)可以用一种近似的完全二叉树来表示,该二叉树除了叶子结点之外,其余节点均具有两个子女,每一个节点都有一个用于排序的关键字key。根据堆顶元素性质,堆可以分为大根堆和小根堆。对于大根堆而言,其堆顶是整棵树最大的节点,并且以其为祖先的每一个节点均是一个大根堆。小根堆反之亦然。堆排序采用大根堆完成,所以我们下面用大根堆来介绍堆的建立。
用一个长为 n n n 的数组表示一棵近似完全二叉树,其下标从0到n-1。那么对于其中的每一个节点,其父节点、左右子女节点可如下表示:
p a r e n t ( i ) = ( i − 1 ) / 2 parent(i) = (i - 1)/2 parent(i)=(i−1)/2
l e f t ( i ) = 2 i + 1 left(i) = 2i + 1 left(i)=2i+1
r i g h t ( i ) = 2 i + 2 right(i) = 2i + 2 right(i)=2i+2
显然,随便拿到的一个数组通常不具备最大堆的性质。以其中一个节点 i 为例,该节点有可能不是以该节点为根的子树中的最大节点。对此,我们的策略是,只要让每一个节点i,均比自己的左右子女大,那么就可以建立起来一个大根堆。
文章目录 1. 背景2. 基于AspectJ注解来实现AOP3. XML实现和注解实现AOP的代码对比4. AOP通知讲解5. AOP时序图 1. 背景 在现代软件开发中,面向切面编程(AOP)是一种强大的编程范式,允许开发者跨越应用程序的多个部分定义横切关注点(如日志记录、事务管理等)。本文将介绍如何在Spring框架中通过AspectJ注解以及对应的XML配置来实现AOP,在不改变主业务逻辑的情况下增强应用程序的功能。
2. 基于AspectJ注解来实现AOP 对于一个使用Maven的Spring项目,需要在pom.xml中添加以下依赖:
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.10</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.9.6</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> </dependency> </dependencies> 确保版本号与使用的Spring版本相匹配,可以自行调整。
创建业务逻辑接口MyService: package com.example.demo.aop; public interface MyService { void performAction(); } 创建业务逻辑类MyServiceImpl.java: package com.example.demo.aop; import org.springframework.stereotype.Service; @Service public class MyServiceImpl implements MyService { @Override public void performAction() { System.out.println("Performing an action in MyService"); } } 定义切面 创建切面类MyAspect.java,并使用注解定义切面和通知:
package com.example.demo.aop; import org.
目录
🌞0.前言
🚈 1.堆的概念
🚈 2.堆的实现
🚝2.1堆向下调整算法
🚝2.2堆的创建(堆向下调整算法)
✈️2.2.1 向下调整建堆时间复杂度
🚝2.3堆向上调整算法
🚝2.4堆的创建(堆向上调整算法)
✈️2.4.1向上调整算法建堆的时间复杂度
🚝2.5堆的插入
🚝2.6堆的删除
🚝2.7建堆的代码实现
✈️2.7.1向下调整实现堆的建立
✈️2.7.2向上调整实现堆的建立
🚈 3.完整的堆的代码的实现
🚝3.1堆的创建
🚝3.2堆的销毁
🚝3.3堆的插入
🚝3.4堆的删除(头删)
🚝3.5取堆顶元素的数据
🚝3.6 堆的数据个数
🚝3.7堆的判空
🚈 4.堆的应用堆排序
✍5.结束语
🌞0.前言 言C之言,聊C之识,以C会友,共向远方。各位博友的各位你们好啊,这里是持续分享数据结构知识的小赵同学,今天要分享的数据结构知识是堆,在这一章,小赵将会向大家展开聊聊堆的相关知识。✊
🚈 1.堆的概念 堆就是以 二叉树的顺序存储方式来存储元素,同时又要满足 父亲结点存储数据都要大于等于儿子结点存储数据(也可以是父亲结点数据都要小于等于儿子结点数据)的一种数据结构。堆只有两种即大堆和小堆,大堆就是父亲结点数据大于等于儿子结点数据,小堆则反之。 同时这里要注意的是堆一定是完全二叉树,不然就不是堆。那完全二叉树是什么呢?这个地方不懂的博友可以看我们的这一篇博客:数据结构(C)树的概念和二叉树初见http://t.csdnimg.cn/JnWfb
如果看完了还是不明白可以私信小赵询问哦。
好了下面让我们看看上面说的两种堆在图上是怎么呈现的呢?
我们发现我们的任意一个父节点都比他的两个子节点大(或等于)这个时候这就是一个大堆。 我们发现我们的任意一个父节点都比他的两个子节点小(或等于)这个时候这就是一个小堆。 虽然堆是完全二叉树,但其的存储方式却与二叉树不同,我们一般存储堆的方式是数组。而我们上面所画的叫逻辑结构,那怎么由数组的存储方式,转化为我们的逻辑结构呢?
我们在介绍二叉树的时候其实也曾简单的说过二叉树是有顺序的,是从上到下,从左向右的,按这个顺序我们就可以给我们的二叉树标序号。 那么就可以我们的逻辑结构转化成我们的数组结构了,既然我们已经会将逻辑结构转化为数组结构了,那么将数组结构转化为逻辑结构也就没有这么难了,大家可以自己试试,如果实在实现不了也可以找小赵咨询哦。 🚈 2.堆的实现 🚝2.1堆向下调整算法 什么是向下调整算法呢?其实正如其名就是从上到下调整堆的意思。要想更深入了解这个东西就先来看这张图。
看这张图这是一个很明显的小堆对吧,那我这个时候要你改成一个大堆怎么办,这个时候的操作其实是2,3进行比较,然后拿出大的和1换这个就成大堆了。 可如果这个时候我给你的是个这样的堆你又该怎么办(要改成小堆)
其实这个时候也是可以操作的,因为下面是有序的堆,我们只需要按照前面的顺序一步步来就可以完成了。只不过这个时候改成了选择两个子中的小的哪一个,因为我们要做得是小堆(这个时候之所以说他下面是有序的堆是因为盖住最上面的一个,下面的两个堆都是小堆,我们要改成的也是小堆。)
那如果是无序的呢? (改成小堆)
这个时候我们发现我们再想把这个改成小堆的难度就很大了。
🚝2.2堆的创建(堆向下调整算法) 那通过上面的实验我们发现,想通过一个位置来做上面的操作,并把整个堆都变成小(大)堆,必须下面就是一个小(大)堆。所以我们的向下调整其实也是从最下面的开始的,而且我们刚刚做的步骤其实就是向下调整。 那么再面对上面那个无序的堆我们也就有方法了。
这个时候我们就可以做到将无序的堆转化成有序的堆了。 那么这个时候我们面对任何一个无序的数组,都可以通过这样的方式将他转化成堆.(至少在逻辑图上可以实现,代码实现下面说)
✈️2.2.1 向下调整建堆时间复杂度 每层节点个数 × 最坏情况向下调整次数:
T(N) = 2^(h-2) × 1 + 2^(h-3) × 2 + … … + 2^1 × (h-2)+2^0*(h-1)
💗个人主页💗
⭐个人专栏——C++学习⭐
💫点击关注🤩一起学习C语言💯💫
目录
导读
1. vector的核心框架接口
2. 构造函数
2.1 基本构造
2.2 拷贝构造(传统写法)
2.3 析构函数
2.4 operator=运算符重载(传统写法)
2.5 swap函数
2.5 operator=运算符重载(现代写法)
3. vector遍历
3.1 size()和capacity()
3.2 operator[]遍历
3.3 迭代器和范围for
4. vector常见函数
4.1 reserve函数
4.2 resize函数
4.3 insert函数
4.4 erase函数
4.5 push_back函数
4.6 pop_back函数
4.7 empty函数
5. 构造函数和拷贝构造完善
5.1 拷贝构造(现代写法)
5.2 构造函数
初始化构造
列表构造
区间构造
6. 代码整理
6.1 vector.h文件
6.2 test.cpp文件
导读 我们在上期讲解了vector的一下基本使用,今天我们来模拟实现一下vector。
1. vector的核心框架接口 vector类有三个成员变量:start,finish和end_of_storage。
这三个成员变量可以用于遍历vector中的元素、确定vector的大小和容量,或者进行其他操作。
start:指向vector中第一个元素的指针或迭代器。它表示vector中数据的起始位置。
finish:指向vector中最后一个元素的下一个位置的指针或迭代器。它表示vector中数据的结束位置。
end_of_storage:指向vector内部存储空间的末尾的指针或迭代器。它表示vector内部存储空间的结束位置。
知识铺垫 复数 C=R+jI 可以看作复平面上的点,则该复数的坐标为(R,I)
欧拉公式 e j θ = c o s θ + j s i n θ e^{j\theta} = cos \theta + j sin \theta ejθ=cosθ+jsinθ
极坐标系中复数可以表示为: C = ∣ C ∣ ( c o s θ + j s i n θ ) C = |C|(cos\theta + j sin \theta) C=∣C∣(cosθ+jsinθ)
所以,由于欧拉公式可以将复数表示为: C = ∣ C ∣ e j θ C=|C|e^{j\theta} C=∣C∣ejθ
傅立叶级数 傅立叶指出,任何周期函数都可以表示为不同频率的正弦和余弦函数之和,每个正弦项和余弦项均乘以不同的系数
同时,根据我们前面掌握的欧拉公式,可以对傅里叶级数的公式进行转换得到:
f ( t ) = ∑ n = − ∞ ∞ c n ⋅ e j 2 π n T t f(t)=\sum\limits_{n=-\infty}^{\infty}c_n\cdot e^{j\frac{2\pi n}{T}t} f(t)=n=−∞∑∞cn⋅ejT2πnt
获取图片主要就是通过必应图片页面控制台的元素,确认图片和标题在哪个类中(浏览器 F12)
引入依赖 这里需要引入两个依赖 jsoup 和 hutool
maven依赖网站地址:Maven Repository: Search/Browse/Explore (mvnrepository.com)
挑选使用最多的版本即可
hutool依赖
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.27</version> </dependency> jsoup 依赖
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup --> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.15.3</version> </dependency> 查看浏览器图片的位置 这里 murl 和 turl 都可以访问,选取一个即可。
使用 jsoup 爬取 1. 首先从 jsoup 官方文档得到示例代码:jsoup: Java HTML parser, built for HTML editing, cleaning, scraping, and XSS safety
Document doc = Jsoup.connect("https://en.wikipedia.org/").get(); log(doc.title()); Elements newsHeadlines = doc.select("#mp-itn b a"); for (Element headline : newsHeadlines) { log("
本文介绍一个统一音频标记(Audio Tagger)和语音识别(ASR)的模型:Whisper-AT,通过冻结Whisper的主干,并在其之上训练一个轻量级的音频标记模型。Whisper-AT在额外计算成本不到1%的情况下,可以在单次前向传递中识别音频事件以及口语文本。这个模型的提出是建立一个有趣的发现基础上:Whisper对真实世界背景声音非常鲁棒,其音频表示实际上并不是噪声不变的,而是与非语音声音高度相关,这表明Whisper是在噪声类型的基础上识别语音的。
1.概述: Whisper-AT 是建立在 Whisper 自动语音识别(ASR)模型基础上的一个模型。Whisper 模型使用了一个包含 68 万小时标注语音的大规模语料库进行训练,这些语料是在各种不同条件下录制的。Whisper 模型以其在现实背景噪音(如音乐)下的鲁棒性著称。尽管如此,其音频表示并非噪音不变,而是与非语音声音高度相关。这意味着 Whisper 在识别语音时会依据背景噪音类型进行调整。
在上述发现的基础上,有一个令人兴奋的应用方式:我们能够基于Whisper构建一个统一的模型,用于自动语音识别(ASR)和音频标记,以同时识别口语文本和背景声音(例如音乐、喇叭等),这在视频转录、语音助手和助听器系统等应用中非常理想。Whisper是这样一个统一模型的理想基础,因为1)它对背景声音具有鲁棒性,2)它的中间表示编码了丰富的一般音频事件信息,这为音频标记提供了坚实的基础。尽管如此,原始的Whisper模型不输出声音标签,所以我们需要在Whisper的中间表示之上训练一个模型,以使其能够预测声音类别。请注意,我们特意不修改原始Whisper模型的权重,而是在其上添加新的音频标记层,以便Whisper的自动语音识别能力不受影响,并且可以在单个前向传递中生成文本和音频标签。我们称这个统一的ASR和音频标记模型为Whisper-AT。
主要发现: 噪音变化的表示:
Whisper 的音频表示编码了丰富的非语音背景声音信息,这与通常追求噪音不变表示的 ASR 模型目标不同。这一特性使得 Whisper 能够在各种噪音条件下通过识别和适应噪音来保持其鲁棒性。 ASR 和音频标签的统一模型:
通过冻结 Whisper 模型的骨干网络,并在其上训练一个轻量级的音频标签模型,Whisper-AT 可以在一次前向传递中同时识别音频事件和语音文本,额外的计算成本不足 1%。Whisper-AT 在音频事件检测方面表现出色,同时保持了 Whisper 的 ASR 功能。 技术细节: Whisper ASR 模型:
Whisper 使用基于 Transformer 的编码器-解码器架构。其训练集包括从互联网上收集的 68 万小时音频-文本对,涵盖了广泛的环境、录音设置、说话人和语言。 抗噪机制:
Whisper 的鲁棒性并非通过噪音不变性实现,而是通过在其表示中编码噪音类型。这一机制使得 Whisper 能够根据背景噪音类型来转录文本,从而在嘈杂条件下表现优越。 构建 Whisper-AT:
Whisper-AT 是通过在 Whisper 模型上添加新的音频标签层而构建的,未修改其原始权重。 探索了不同的音频标签层集成方法,包括: Last-MLP:对 Whisper 的最后一层表示进行时间均值池化,然后应用线性层。WA-MLP:对所有层的表示进行加权平均,然后应用线性层。WA-Tr:用时间 Transformer 层替换线性层。TL-Tr:使用时间和层次 Transformer 处理所有层的表示。 效率考量:
为保持计算效率,采用了各种策略,例如减少表示的序列长度,并在应用音频标签 Transformer 之前可选地降低维度。 性能: Whisper-AT 在 AudioSet 上达到了 41.
1.如何在Spring Boot中配置MySQL数据库的连接数 1.1主要配置 在Spring Boot中配置MySQL数据库连接数通常涉及到两个主要的配置:
(1)数据源配置:这通常是在application.properties或application.yml文件中完成的,用于设置数据源的基本参数,如URL、用户名、密码等。
(2)连接池配置:Spring Boot默认使用HikariCP作为连接池,但我们也可以选择其他的连接池(如Tomcat JDBC Pool、DBCP等)。连接池的配置会影响到连接数的创建、验证、最大/最小空闲连接等。
1.2Spring Boot项目如何配置MySQL数据库连接数的详细步骤 以下是基于HikariCP的Spring Boot项目如何配置MySQL数据库连接数的详细步骤:
(1)添加依赖
首先,确保我们的pom.xml文件中包含了Spring Boot的starter-data-jpa或starter-jdbc依赖,这将自动引入HikariCP作为连接池。
<dependencies> <!-- ... 其他依赖 ... --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- ... 其他依赖 ... --> </dependencies> (2)** 配置数据源**
在application.properties或application.yml文件中配置数据源。以下是一个application.properties的示例:
# 数据源配置 spring.datasource.url=jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC spring.datasource.username=your_username spring.datasource.password=your_password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # HikariCP连接池配置 spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.maximum-pool-size=10 spring.datasource.hikari.idle-timeout=30000 spring.datasource.hikari.max-lifetime=1800000 spring.datasource.hikari.connection-timeout=30000 spring.datasource.hikari.connection-test-query=SELECT 1 minimum-idle:空闲连接的最小数量。
maximum-pool-size:连接池的最大连接数。
idle-timeout:空闲连接超时时间(毫秒)。
max-lifetime:连接的最大生命周期(毫秒)。
connection-timeout:连接超时时间(毫秒)。
connection-test-query:用于测试连接的SQL查询。
(3)(可选)自定义数据源配置
如果我们需要更复杂的配置或想要完全自定义数据源,我们可以创建一个配置类并使用@Bean注解来定义我们的数据源。但通常情况下,上面的属性配置就足够了。
(4)注意事项
确保MySQL服务正在运行,并且我们提供的URL、用户名和密码是正确的。
根据我们的需要调整连接池的参数。上述参数只是示例,我们可能需要根据我们的应用程序的特性和数据库服务器的性能进行调整。
如果我们的应用程序在高并发环境下运行,可能需要增加maximum-pool-size的值以避免连接不足的问题。但同时也要注意,设置太高的值可能会导致资源浪费和数据库服务器性能下降。
监控我们的数据库连接池的使用情况,并根据需要进行调整。我们可以使用Spring Boot的Actuator模块来暴露连接池的健康和度量信息。
文章目录 两个基础知识1. react的更新问题, react更新会重新执行react函数组件方法本身,并且子组件也会一起更新2. useCallback和useMemo滥用useCallback和useMemo要解决什么3. react的state有个经典的闭包,导致拿不到最新数据的问题.常见于useEffect, useMemo, useCallback4. 副作用方案总结 两个基础知识 1. react的更新问题, react更新会重新执行react函数组件方法本身,并且子组件也会一起更新 2. useCallback和useMemo滥用 useCallback和useMemo要解决什么 React.memo包装组件
React.useCallback包裹传递子组件函数
对于传递给组件的对象是固定不变的,和数据没有关系的.
需要将固定变量放在函数外层
React.useMemo: 当你给子组件的对象是和组件数据有关的, 也就是做一个计算属性时候
, 采用useMemo
3. react的state有个经典的闭包,导致拿不到最新数据的问题. 常见于useEffect, useMemo, useCallback 4. 副作用方案 App.jsx
import React, { useState, useRef, useEffect } from 'react' import Filter from './components/Filter'; import Pagers from './components/Pagers'; import './App.css' // * 如果这个对象是固定不变的,和state数据无关系, 需要提到组件外侧 const obj = { a:'cccc' } // useRef, 副作用方案 // 如果有一个state数据, 需要传递给子组件时候 // 建议把state数据定义为ref function App() { const [count, setCount] = useState(0) const [filterData, setFilterData] = useState('') const [pageData, sePageData] = useState('') // useRef: // 当有一个变量, 当这个变量不想被外部获取, 不需要写依赖 // 并且还想获取state最新值, 此时,需要将state变为ref // useRef定义的变量【不会造成视图更新】 // const filterData = useRef('') // const setFilterData = React.
系列文章目录 文章目录 系列文章目录前言一、本文要点二、开发环境三、原项目四、修改项目五、测试一下五、小结 前言 本插件稳定运行上百个kafka项目,每天处理上亿级的数据的精简小插件,快速上手。
<dependency> <groupId>io.github.vipjoey</groupId> <artifactId>multi-kafka-consumer-starter</artifactId> <version>最新版本号</version> </dependency> 例如下面这样简单的配置就完成SpringBoot和kafka的整合,我们只需要关心com.mmc.multi.kafka.starter.OneProcessor和com.mmc.multi.kafka.starter.TwoProcessor 这两个Service的代码开发。
## topic1的kafka配置 spring.kafka.one.enabled=true spring.kafka.one.consumer.bootstrapServers=${spring.embedded.kafka.brokers} spring.kafka.one.topic=mmc-topic-one spring.kafka.one.group-id=group-consumer-one spring.kafka.one.processor=com.mmc.multi.kafka.starter.OneProcessor // 业务处理类名称 spring.kafka.one.consumer.auto-offset-reset=latest spring.kafka.one.consumer.max-poll-records=10 spring.kafka.one.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer spring.kafka.one.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer ## topic2的kafka配置 spring.kafka.two.enabled=true spring.kafka.two.consumer.bootstrapServers=${spring.embedded.kafka.brokers} spring.kafka.two.topic=mmc-topic-two spring.kafka.two.group-id=group-consumer-two spring.kafka.two.processor=com.mmc.multi.kafka.starter.TwoProcessor // 业务处理类名称 spring.kafka.two.consumer.auto-offset-reset=latest spring.kafka.two.consumer.max-poll-records=10 spring.kafka.two.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer spring.kafka.two.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer ## pb 消息消费者 spring.kafka.pb.enabled=true spring.kafka.pb.consumer.bootstrapServers=${spring.embedded.kafka.brokers} spring.kafka.pb.topic=mmc-topic-pb spring.kafka.pb.group-id=group-consumer-pb spring.kafka.pb.processor=pbProcessor spring.kafka.pb.consumer.auto-offset-reset=latest spring.kafka.pb.consumer.max-poll-records=10 spring.kafka.pb.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer spring.kafka.pb.consumer.value-deserializer=org.apache.kafka.common.serialization.ByteArrayDeserializer 国籍惯例,先上源码:Github源码
一、本文要点 本文将介绍通过封装一个starter,来实现多kafka数据源的配置,通过通过源码,可以学习以下特性。系列文章完整目录
SpringBoot 整合多个kafka数据源SpringBoot 批量消费kafka消息SpringBoot 优雅地启动或停止消费kafkaSpringBoot kafka本地单元测试(免集群)SpringBoot 利用map注入多份配置SpringBoot BeanPostProcessor 后置处理器使用方式SpringBoot 将自定义类注册到IOC容器SpringBoot 注入bean到自定义类成员变量Springboot 取消限定符Springboot 支持消费protobuf类型的kafka消息Springboot Aware设计模式Springboot 获取kafka消息中的topic、offset、partition、header等参数 二、开发环境 jdk 1.