✨✨ 欢迎大家来到贝蒂大讲堂✨✨
🎈🎈养成好习惯,先赞后看哦~🎈🎈
所属专栏:数据结构与算法
贝蒂的主页:Betty’s blog
1. 树 1.1. 树的定义 树是一种非线性的数据结构,它是由n(n >= 0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
在树中有一个特殊的结点,称为根结点,根节点没有前驱结点
除根节点外,其余结点被分成M(M > 0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1 <= i<= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继因此,树是递归定义的。
注意:树形结构中,子树之间不能有交集,否则就不是树形结构
1.2. 树的基本概念 术语定义节点的度一个节点含有的子树的个数称为该节点的度,比如说节点1的度为2叶节点度为0的节点,比如说4,5,6节点分支节点度不为0的节点,比如说2,3节点双亲节点若一个节点含有子节点,则这个节点称为其子节点的父节点。比如说2是4,5的双亲节点子节点一个节点含有的子树的根节点称为该节点的子节点,比如说4,5是2的子节点兄弟节点具有相同父节点的节点互称为兄弟节点,比如说4,5就是兄弟节点树的度一棵树中,最大的节点的度称为树的度,比如说上面这棵树的度为2节点的层次从根开始定义起,根为第1层,根的子节点为第2层,以此类推树的高度或深度树中节点的最大层次,比如说上面这棵树的高度为3堂兄弟节点双亲在同一层的节点互为堂兄弟,比如说5,6节点节点的祖先从根到该节点所经分支上的所有节点,比如说1就是所有节点的祖先子孙以某节点为根的子树中任一节点都称为该节点的子孙,比如说所有节点都是1的子孙森林由m(m>0)棵互不相交的树的集合称为森林 1.3. 树的表示方法 下面我们将采用三种方式表示下面这课树:
1.3.1. 双亲表示法 双亲表示法采用顺序表的方式存储,即用顺序表存储各个节点的数据,并且同时存储其双亲节点的下标。注意:根节点没有双亲节点,所以特别记为-1。
#define MAX_SIZE 10 typedef int DataType; typedef struct Node { DataType data;//数据域 int parent; //双亲结点在数组中的位置下标 }Node; typedef struct PTree { //存放树中所有结点 Node tnode[MAX_SIZE]; //当前结点个数 int n; }PTree; 1.3.2. 树的孩子表示法 树的孩子表示法就是采用顺序表与链表结合的形式,用顺序表存储树的值与链表的头节点,而链表的头节点存储其孩子节点在顺序表中的下标,若没有则记为空(N)。
#define MAX_SIZE 10 #define DataType int typedef struct ListNode { int child; struct ListNode* next; }ListNode; typedef struct TNode { DataType data; //孩子链表的头指针 ListNode* firstchild; }TNode; typedef struct PTree{ //存储结点的数组 TNode nodes[MAX_SIZE]; int n; //结点数量 }PTree; 1.
目录
1.前言
2.HDFS
2.1.指令操作
2.2.JAVA API
3.HBase
3.1.指令操作
3.2.JAVA API
1.前言 本文是作者大数据专栏系列的其中一篇,前文中已经详细聊过分布式文件系统HDFS和分布式数据库HBase了,本文将会是它们的实操讲解。
HDFS相关前文:
【大数据】分布式文件系统HDFS-CSDN博客
【大数据】大数据概论与Hadoop_大数据导论与hadoop-CSDN博客
HBase相关前文:
【大数据】分布式数据库HBase-CSDN博客
【大数据】分布式数据库HBase下载安装教程-CSDN博客
2.HDFS 2.1.指令操作 创建目录:
hdfs dfs -mkdir /user/mydir
递归创建目录:
hdfs dfs -mkdir -p /user/mydir/subdir
上传文件到HDFS:
hdfs dfs -put localfile.txt /user/mydir/
下载文件到本地:
hdfs dfs -get /user/mydir/file.txt localdir/
删除文件:
hdfs dfs -rm /user/mydir/file.txt
递归删除目录:
hdfs dfs -rm -r /user/mydir
查看目录内容:
hdfs dfs -ls /user/mydir
递归查看目录内容:
hdfs dfs -lsr /user/mydir
查看文件详细信息:
hdfs dfs -stat /user/mydir/file.txt
文章目录 0. 前言1. 多态类的概念2. Python中实现多态类的途径2.1 类的继承2.2 抽象基类2.3 duck typing 3. 多态类的应用场景4. 结论 0. 前言 按照国际惯例,首先声明:本文只是我自己学习的理解,虽然参考了他人的宝贵见解及成果,但是内容可能存在不准确的地方。如果发现文中错误,希望批评指正,共同进步。
本文介绍Python中的类的特征之一——多态性,核心是介绍多态类的实现途径。
在面向对象编程(OOP)中,多态是三大核心特性之一,与封装和继承并列。它赋予了程序更高的灵活性、可扩展性和可维护性。Python作为一门支持全面OOP特性的高级语言,其对多态的支持尤为出色。本文将详细介绍Python中多态类的概念、实现方式以及实际应用场景,旨在帮助读者深入理解并有效运用Python多态类。
1. 多态类的概念 多态,简单来说,是指同一操作作用于不同对象时,可以产生不同的行为。在Python中,这种“同一操作”通常表现为方法调用,而“不同对象”则指代具有相同接口(即方法名)但具体实现各异的类实例。多态的核心价值在于,它允许程序员以统一的方式处理多种数据类型,无需关注具体的类型细节,从而提升代码的抽象层次和复用性。
2. Python中实现多态类的途径 2.1 类的继承 这是实现多态最直接的方式。子类通过继承父类并重写其部分或全部方法,使得相同的方法名在不同子类中表现出不同的行为。例如:
class Animal: def make_sound(self): pass class Dog(Animal): def make_sound(self): return "Woof!" class Cat(Animal): def make_sound(self): return "Meow!" dog = Dog() cat = Cat() print(dog.make_sound()) # 输出: Woof! print(cat.make_sound()) # 输出: Meow! 在这个例子中,Dog和Cat类都继承自Animal类并重写了make_sound方法,实现了多态。尽管调用的是同名方法,但由于对象类型不同,实际执行的行为也各异。
2.2 抽象基类 Python提供了abc(Abstract Base Classes)模块来定义抽象基类,这些类包含抽象方法(未实现的方法),要求其子类必须实现这些方法。这为多态提供了一种形式化的约束机制。例如:
import abc class Shape(metaclass=abc.ABCMeta): @abc.abstractmethod def area(self): pass class Circle(Shape): def __init__(self, radius): self.
目录
1.什么是LSM树?
2.LSM树的落地实现
1.什么是LSM树? LSM树(Log-Structured Merge Tree)是一种专门针对大量写操作做了优化的数据存储结构,尤其适用于现代大规模数据处理系统,如NoSQL数据库(如Cassandra、HBase、RocksDB等)和键值存储。尽管其名称中包含“树”,但它并不直接对应于传统的树状数据结构,而是指一种数据管理策略或体系架构。
LSM为什么会出现:
当数据量大了之后,读操作采用顺序遍历来进行查找肯能是不行的,性能太低了。所以需要维护一种数据结构用来帮助提升读的效率,在关系型数据库中用B+树(索引)来维护数据的关系,便于查找。
B树和B+树详细内容可移步作者的另一篇文章,作者有个数据结构专栏,专门讲解了所有常用数据结构:
数据结构(8)树形结构——B树、B+树(含完整建树过程)_排序好的数怎么画b+树-CSDN博客
关系型数据库中对B+树的使用在读的时候性能不错,但是在写的时候存在明显的性能问题。不是说B+树这种数据结构在写的时候存在性能问题,而是关系型数据库中是将树结构存在磁盘上的,并且树的节点在磁盘上的存储是分散的,数据的存储也是分散的,这种落地方式在面对写操作的时候会有性能瓶颈。
原因如下:
首先是写操作。写操作是容易引起B+树的结构的调整的,要调整树的结构当然要去读写树的节点,树的整个结构都存在磁盘上的,所以要走磁盘IO,调整树当然就要去对磁盘上存的树的节点进行读写,B+树在磁盘中的存储是分散的,所以这里的IO是随机IO。写数据的时候,数据也不是顺序存放的,也是分散存放的,也会是随机IO。
其次是读操作,即使B+树尽力优化了树的层高,减少了磁盘IO次数,但是毕竟树的节点和数据不是顺序写入进行存储的,所以在访问的时候还是会进行随机IO,在关系型数据库的场景下倒是没什么问题,在大数据场景下要读的数据量是海量的,海量数据都是进行随机IO的读,性能上来说也是不佳的。
所以在海量数据的写入的时候B+树不是一个优质的选择。对着大数据场景的出现,LSM树出现,用于专门应对海量数据的写入。
总结一下B+树面对海量数据无力是因为:
树存在磁盘上,读写都是磁盘IO
树是分散存放的,读写都是随机IO
数据是分散存放的,读写都是随机IO
LSM树其实就是一套打法,核心目的就是为了规避上面的问题。
LSM树会将树结构放在内存中,从而规避磁盘IO,当然内存是有限的,到了一定条件后会将当前内存中这个版本的树存到磁盘中,存磁盘的时候开辟一块连续空间,将树的节点连续存储在一起,然后刷新内存再重新开始存新进来的内容。读的时候就会先去读内存,内存中没有再去读磁盘。由于磁盘中树的节点是连续写在一起的,会减少随机IO。
当在落磁盘的时候,磁盘上如果有历史版本的话,会和最新的历史版本进行合并。也就是说越新的历史版本,树越”茂盛“:
2.LSM树的落地实现 LSM树的落地实现通常包含内存中的MemTable(内存表)和磁盘上的SSTable(Sorted String Table,有序字符串表)两部分。
数据首先写入内存中的MemTable,数据在memtable中就会被组织成平衡二叉树:
当MemTable达到一定大小时,会被转换为不可变的SSTable并刷写到磁盘,写入磁盘的时候会开辟一段连续的存储空间,将树的内容连续存储在一起:
除了上面的内容外,还有一个核心内容——Compaction,合并。
由于肯定会落多次磁盘,生成多个版本的sstable,会浪费磁盘空间,所以还会存在合并操作,将多棵小树合成一棵大树。合并的时机一般有两个:
一个时机是在落磁盘生成新的sstable的时候会和之前最新的历史版本对应的sstable进行一次合并,两棵小树合并出一棵大树来。另一个时机是磁盘的存储达到一定阈值之后多个历史版本的sstable会进行合并合并出一棵大树来。
还有最后一个问题就是如何删除LSM树中的元素?
在memtable中删除了,但是sstable中还有,直接删除是没有用的,下次合并的时候还是会把已经删除的元素合并进来。所以LSM的做法是给要删除的元素打上一个墓碑标记,墓碑标记用来标记数据被删除了,下次合并的时候就能通过墓碑标记来判断哪些元素不用合并进来。
❣博主主页: 33的博客❣
▶️文章专栏分类:JavaEE◀️
🚚我的代码仓库: 33的代码仓库🚚
🫵🫵🫵关注我带你了解更多文件操作
目录 1.前言2.认识文件3.文件操作3.1File 属性3.2构造方法3.3File类方法 4.文件内容操作4.1Reader4.2writer4.3inputStream4.4OutputStream4.5字符流与字节流转换 5.应用6.总结 1.前言 2.认识文件 操作系统中,会把硬盘设备和软件资源抽象为文件,但大多数情况下谈到文件就是指硬盘中的文件。
文件是以树型结构组织的:以此电脑为根节点的n叉树
文件路径:
如何在文件系统中描述一个文件的位置,因为从树型结构的角度来看,树中的每个结点都可以被一条从根开始,一直到达的结点的路径所描述,而这种描述方式就被称为文件的绝对路径(absolute path)。
除了使用绝路径来描述以外,还可以用相对路径来表示一个文件的位置
. 表示当前目录
. . 表示当前目录的上一级目录
文件类型:
二进制文件:文件是以二进制形式存储数据,不要求保存的内容是合法的字符
文本文件:文件是以纯文本形式存储数据,保存的内容都是合法的字符
判断一个文件是哪种类型,最简单的方式就是以文本的方式打开一个文件,观察是否出现乱码,如果乱码就是二进制文件否则为文本文件。
例如我打开一个图片:
3.文件操作 我们主要涉及文件的元信息、路径的操作,暂时不涉及关于文件中内容的读写操作。
Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。注意,有 File 对象,并不代表真实存在该文件。
3.1File 属性 路径中用来分割的符号,在Windows中’/‘或者’’
3.2构造方法 3.3File类方法 public static void main(String[] args) { File file=new File("d:/test"); System.out.println(file.getName());//获取父目录纯文件名称 System.out.println(file.getParent());//获取父目录路径 System.out.println(file.getPath());//获取file的路径 System.out.println(file.getAbsolutePath());//获取file的绝对路径 } public static void main(String[] args) throws IOException { File file=new File("d:/test/test.txt"); System.out.println(file.exists());//判断file是否存在 System.out.println(file.isDirectory());//判断file是否为目录 System.
登神长阶
第十神装 HashSet
第十一神装 HashMap
目录
👔一.哈希
🧥1.概念
🩳2.Object类的hashCode()方法:
👚3.String类的哈希码:
👠4.注意事项:
🎷二.哈希桶
🪗1.哈希桶原理
🎸2.哈希桶的实现细节
🪘3.总结
📲三.解决哈希冲突的常用方法*
💰四.HashSet
🪙1.定义
💵2.操作
💶3.特性
💷4.内部实现
💳5.应用场景
✏️五.HashMap
✒️1.定义
🖋️2.操作
🖊️3.特性
🖍️4.内部实现
🖌️5.应用场景
📝六.对比
💼七.总结与反思
👔一.哈希 🧥1.概念 在Java中,哈希(Hash)是一个广泛应用于数据结构和算法中的概念,主要用于快速查找、存储和比较数据。哈希的核心在于哈希函数(Hash Function),它将输入(通常称为键,key)映射到一个固定范围的输出值,这个输出值称为哈希值(Hash Value)或哈希码(HashCode)。哈希的目的在于将原本复杂、不规则的数据转化为简洁的、固定长度的值,使得数据的存储和检索更加高效。
🩳2.Object类的hashCode()方法: Java中的每个对象都继承自Object类,而Object类有一个hashCode()方法,这个方法被设计用来返回对象的哈希码。默认的hashCode()实现通常基于对象的内存地址,但子类通常会重写此方法,以便根据对象的实际内容生成更有意义的哈希值,这对于使用对象作为键的哈希表操作尤为重要。
作用:
hashCode()方法返回对象的哈希码值(哈希码),是一个int类型的整数。哈希码是根据对象的内存地址或者根据对象的内容计算得到的一个唯一标识符。在Java中,hashCode()方法通常与equals()方法一起使用,用于判断两个对象是否相等。 默认实现:
在Object类中,hashCode()方法的默认实现是根据对象的内存地址计算得到的哈希码。换句话说,如果两个对象在内存中的地址不同,那么它们的哈希码也会不同。 重写规则:
在自定义类中,通常需要重写hashCode()方法,以便根据对象的内容来生成哈希码,而不是依赖于默认的内存地址。如果重写了equals()方法,就应该同时重写hashCode()方法,保证相等的对象拥有相等的哈希码。重写hashCode()方法时,应该遵循以下规则: 相等的对象必须具有相等的哈希码。不相等的对象尽量产生不同的哈希码,以减少哈希冲突的发生。 使用场景:
在集合类中,如HashMap、HashSet等,hashCode()方法被用于确定对象在集合中的存储位置,加快数据的查找速度。当我们需要比较自定义类的对象是否相等时,通常会重写equals()和hashCode()方法。 总之,Object类的hashCode()方法是用于获取对象的哈希码的方法,可以通过重写该方法来根据对象的内容生成哈希码,以便在集合中进行快速查找和比较。
👚3.String类的哈希码: String类是一个典型重写了hashCode()方法的类,它根据字符串的内容计算哈希值,这意味着内容相同的字符串将拥有相同的哈希值,这有助于在哈希表中快速定位和比较字符串。
👠4.注意事项: 哈希函数应该是高效的,即计算速度快。哈希函数应该尽量均匀分布,以减少哈希冲突。哈希值虽然可以用于快速比较,但不保证绝对唯一,因此在判断对象相等时,除了比较哈希值外,还需要比较对象的实际内容(通过equals()方法)。在实现自定义类的hashCode()时,应当遵守与equals()方法的一致性原则,即如果两个对象通过equals()判断为相等,它们的哈希码也必须相等。反之,哈希码相等的对象不一定通过equals()判断相等。 🎷二.哈希桶 哈希桶(Hash Bucket)是哈希表(Hash Table)中用于解决哈希冲突的一种常用方法,它是哈希表数据结构的一个重要组成部分。哈希桶是哈希表中存储元素的地方,通常是一个数组。每个桶都有一个索引,通过哈希函数计算得到的哈希值会决定元素被放置在哪个桶中。
🪗1.哈希桶原理 哈希桶解决哈希冲突的方法是,将哈希表的每个槽(或索引)扩展为一个“桶”(Bucket),这个桶本质上是一个数据结构(通常是链表、数组或其他容器),可以存储多个具有相同哈希值的元素。具体来说,当一个键通过哈希函数计算得到的索引已经有其他元素时,新的元素会被添加到这个索引对应的桶中,而不是覆盖原有的元素。
🎸2.哈希桶的实现细节 哈希函数:用于将键转换成索引。好的哈希函数能够尽量均匀地分布元素,减少冲突。
桶的实现:常用的桶实现是链表,因为链表插入和删除操作的时间复杂度较低。但在Java 8以后的HashMap中,当桶中的元素数量达到一定阈值时,会将链表转换为红黑树,以进一步优化查询性能。
负载因子:表示哈希表中已填入元素的数量与哈希表长度的比例,用于衡量哈希表的填充程度。当负载因子超过某个预设值时,哈希表会进行扩容,重新调整大小,以减少冲突,保持高效性能。
扩容:扩容通常涉及创建一个新的、更大容量的哈希表,并将原哈希表中的所有元素重新哈希到新表中。这个过程可以确保桶的平均长度减少,从而减少冲突。
冲突处理:当多个键映射到同一索引时,桶中的链表(或红黑树)结构用于存储这些冲突的键值对,并通过遍历链表(或树)来查找具体的元素。
🎹源代码模拟实现
// key-value 模型 public class HashBucket { private static class Node { private int key; private int value; Node next; public Node(int key, int value) { this.
🔥 个人主页:空白诗 文章目录 🎮 引言❓ 什么是防抖和节流🏹 防抖(Debounce) - 锁定追击,精确无误📌 基础概念📌 适用场景📌 实战代码:防抖 应用于输入框的实时搜索 🌀 节流(Throttle) - 技能冷却,战略部署📌 基础概念📌 适用场景📌 实战代码:节流 应用于点击按钮事件 🏆 结语🔗 相关链接 🎮 引言 在前端开发的实践里,确保用户界面流畅且高效是至关重要的。面对诸如窗口滚动、输入监听等高频触发事件,防抖(Debounce) 和 节流(Throttle) 技术成为了优化性能、提升用户体验的关键策略。本篇学习笔记旨在通过直接的概念阐述、详尽的原理分析及实战代码示例(含注释),帮助你全面掌握这两种优化方法。🌟
❓ 什么是防抖和节流 「防抖」(Debounce)和「节流」(Throttle)是两种在软件开发中用来优化高性能需求环境下事件处理的技术,主要目的是限制函数的执行频率,从而减少不必要的计算负担,提高程序效率,尤其是在处理高频触发的事件如用户输入、滚动事件或窗口大小调整时。
🏹 防抖(Debounce) - 锁定追击,精确无误 📌 基础概念 「防抖」的核心在于,当一个动作被触发时,并不立即执行相应函数,而是设置一个延迟(等待)时间。若在这个延迟时间内再次触发该动作,则重新开始计时,直到延迟时间结束后,函数才会被执行一次。此机制有效避免了因短时间内频繁操作而造成的资源浪费。
📌 适用场景 「防抖」非常适合用于处理那些用户连续且快速的操作,如表单的实时验证、搜索框的自动完成建议。它确保在用户停止操作后才进行响应,比如键盘输入停止后才发送请求获取搜索建议,这样可以避免用户还在输入过程中就频繁发送请求。
想象你是游戏中的一名狙击手,面对快速移动的目标。防抖技能就像是你的高级锁定系统:一旦发现敌人,你立刻启动锁定程序,但敌人如果在你完成锁定前不断变换位置,你的瞄准镜就会不断调整,重新开始锁定流程。只有当敌人在一段时间内保持静止(例如1秒),你的锁定系统才能最终确定目标位置,发射致命一击。这样一来,你确保了每一枪都是在最理想的条件下发射,避免了无谓的资源浪费。🎯
📌 实战代码:防抖 应用于输入框的实时搜索 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Debounce Input Example</title> <style> body { font-family: Arial, sans-serif; } #searchInput { width: 300px; padding: 10px; margin-bottom: 10px; } #searchResult { margin-top: 10px; } </style> </head> <body> <h2>防抖输入框示例</h2> <input type="
基于SpringAI搭建系统,依靠线程池、负载均衡等技术进行请求优化,用于解决科研&开发过程中对GPT接口进行批量化接口请求中出现的问题。
github地址:https://github.com/linkcao/springai-wave
大语言模型接口以OpenAI的GPT 3.5为例,JDK版本为17,其他依赖版本可见仓库pom.xml
拟解决的问题 在处理大量提示文本时,存在以下挑战:
API密钥请求限制: 大部分AI服务提供商对API密钥的请求次数有限制,单个密钥每分钟只能发送有限数量的请求。处理速度慢: 大量的提示文本需要逐条发送请求,处理速度较慢,影响效率。结果保存和分析困难: 处理完成的结果需要保存到本地数据库中,并进行后续的数据分析,但这一过程相对复杂。 解决方案 为了解决上述问题,本文提出了一种基于Spring框架的批量化提示访问方案,如下图所示:
其中具体包括以下步骤:
多线程处理提示文本: 将每个提示文本看作一个独立的任务,采用线程池的方式进行多线程处理,提高处理效率。动态分配API密钥: 在线程池初始化时,通过读取本地数据库中存储的API密钥信息,动态分配每个线程单元所携带的密钥,实现负载均衡。结果保存和管理: 在请求完成后,将每个请求的问题和回答保存到本地数据库中,以便后续的数据分析和管理。状态实时更新: 将整个批量请求任务区分为进行中、失败和完成状态,并通过数据库保存状态码实时更新任务状态,方便监控和管理。 关键代码示例 多线程异步请求提示信息(所在包: ChatService) // 线程池初始化 private static final ExecutorService executor = Executors.newFixedThreadPool(10); /** * 多线程请求提示 * @param prompts * @param user * @param task * @return */ @Async public CompletableFuture<Void> processPrompts(List<String> prompts, Users user, Task task) { for (int i = 0; i < prompts.size();i++) { int finalI = i; // 提交任务 executor.
1.数组的定义 在Java中,数组是一种相同数据类型的集合。数组在内存中是一段连续的空间。
2.数组的创建和初始化 2.1数组的创建 在Java中,数组创建的形式与C语言又所不同。
Java中数组创建的形式
T[] 数组名 = new T[N]; 1.T表示数组存放的数据类型。
2.T[]表示数组的类型。
3.N表示数组的长度。 2.2数组的初始化 数组的初始化分为动态初始化和静态初始化两种。
2.2.1 动态初始化
动态初始化就是在创建数组的时候,直接指定数组元素的个数。
如以下代码
int[]arr=new int[10];//10就是数组元素个数 2.2.2 静态初始化 静态初始化就是在创建数组的时候不指定数组中元素的个数,但指定数组的内容。
语法格式:
T[] 数组名称=new int[]{data1,data2,data3.....}; 举例说明
public static void main(String[] args) { int[] arr=new int[]{1,2,3,4,5}; String[] man=new String[]{"red","man","lebron"}; double[] arr2=new double[]{1.2,1.2,2.5}; } 注意事项:
1.在Java中,数组在创建的同时不能同时指定数组的长度和数组的内容。否则就会报错。
public class CSDN { public static void main(String[] args) { int[] arr=new int[5]{1,2,3,4,5}; String[] man=new String[4]{"red","man","lebron"}; double[] arr2=new double[5]{1.2,1.2,2.5}; } } 如上面同时所示,同时指定数组的长度和数组的内容就会报错。
🔥个人主页:Quitecoder
🔥专栏:c++笔记仓
朋友们大家好,通过本篇文章,来详细理解多态的内容
目录 `1.多态的定义及实现``1.1多态的构成条件``1.2虚函数的重写``1.3 C++11 override 和 final``1.4重载、覆盖(重写)、隐藏(重定义)的对比` `2.多态的原理``2.1虚函数表``2.2多态的原理``2.3单继承的虚函数表` `3.抽象类``3.1接口继承与实现继承``3.2静态多态与动态多态``3.3例题` `4.多继承中的虚函数表``4.1菱形继承和菱形虚拟继承``4.2菱形虚拟继承:` `5.虚表的存储位置` 1.多态的定义及实现 多态的基本概念:多态指的是对象可以通过指向它们的基类的引用或指针被操纵,同时还能保持其派生类部分的特性。将派生类对象当作基类对象来对待,这允许不同类的对象响应相同的消息以不同的方式,换句话说,同一个接口,使用不同的实例而执行不同操作
比如买票,普通人买票时,是全价买票;学生买票时,是半价买票
class Person { public: virtual void BuyTicket() { cout << "买票-全价" << endl; } }; class Student : public Person { public: virtual void BuyTicket() { cout << "买票-半价" << endl; } }; void Func(Person& p) { p.BuyTicket(); } int main() { Person ps; Student st; Func(ps); Func(st); return 0; } 普通人全价,学生半价
1.1多态的构成条件 多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Student继承了Person。Person对象买票全价,Student对象买票半价
🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍
文章目录
1.0 请求响应概述
1.1 简单参数
1.2 实体参数
2.3 数组集合参数
2.4 日期参数
2.5 json 参数
2.6 路径参数
3.0 完整代码
1.0 请求响应概述 当客户端发送不同的请求参数到服务端,服务端就需要进行不同的方法方式来接收请求参数。一般的请求参数的类型包括:简单参数、实体参数、数组集合参数、日期参数、json 参数、路径参数。
1.1 简单参数 客户端无论通过 get 或者是 post 方式来发送请求,对应发送简单请求参数来说,是通过键值对的方式来发送到服务端。
1)方法一:服务端可以用到 HttpServletRequest 类对象来接收简单参数请求,再通过对象名.getParam("请求参数名") 方法来获取值。
代码演示:
//接收简单参数方法一:使用 HttpServletRequest 类来获取客户端发送过来的请求参数 //通过对象名.get //这里注解为:请求路径 @RequestMapping("/simpleParam") public String simpleParam(HttpServletRequest request){ String name = request.getParameter("name"); String age = request.getParameter("age"); 发送的请求参数:
通过 GET 方式来发送请求,请求参数有两个 name 和 age,send 发送给服务端后,服务端给客户端返回 "OK" 。
服务器输出的结果:
服务端成功接收请求参数且返回数据到客户端。
2)方法二:可以直接用一一对应的方式来接收请求参数,必须要注意保持请求的参数名与服务端需要接收的变量名保持一致。
代码演示:
文章目录 1. 架构图2. helm 安装operator3. 集群知识k8s上的两种模式:Native和Standalone两种CR 4. 运行集群实例Demo1:Application 集群Demo2:Session集群优劣 5. 高可用部署问题1:High availability should be enabled when starting standby JobManagers问题2:The base directory of the JobResultStore isn't accessible 6. 补充 1. 架构图 参考:部署验证demo
2. helm 安装operator 安装cert-manager依赖
Jetstack/cert-manager 是 Kubernetes 生态系统中的一款开源项目,它提供了一种自动化的方式来管理 TLS 证书的生命周期
kubectl create -f https://github.com/jetstack/cert-manager/releases/download/v1.8.2/cert-manager.yaml # helm 安装 , 包含 deploy*1 、cm*1、crd*2 以及 rbac sa webhook kubectl create -f https://github.com/jetstack/cert-manager/releases/download/v1.8.2/cert-manager.yaml helm repo add flink-operator-repo https://downloads.apache.org/flink/flink-kubernetes-operator-1.7.0/ helm install flink-kubernetes-operator flink-operator-repo/flink-kubernetes-operator 3.
˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱
ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶
个人主页:xiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
系列专栏: xiaoxie的redis学习系列专栏——CSDN博客●'ᴗ'σσணღ
我的目标:"团团等我💪( ◡̀_◡́ ҂)" ( ⸝⸝⸝›ᴥ‹⸝⸝⸝ )欢迎各位→点赞👍 + 收藏⭐️ + 留言📝+关注(互三必回)!
目录
编辑 一.五种常用数据类型和内部编码
1.五种常用数据类型和内部编码
2.内部编码方式
1.string 类型 2.hash类型
3.list类型
4.set类型
5.zset(有序集合)类型
6.Redis这样设计有两个好处:
3.单线程架构
redis单线程为什么可以做到高性能?(面试重点)
二.字符串类型的总结
1.字符串类型的常用命令
1.set 及其选项
1.普通的set语句
2. nx选项
3. xx选项
4. ex seconds 或 px milliseconds 选项
2.get命令
3.mset,mget
2.计数命令
1.incr / decr 2.incrby / decrby
3.incrbyfloat
3.其他命令
1.APPEND
📝个人主页:五敷有你 🔥系列专栏:面经
⛺️稳中求进,晒太阳
表级锁 介绍 对于表锁,分为两类:
表共享读锁表独占写锁 语法 1. 加锁:lock tables 表名... read/write
2. 释放锁:unlock tables /客户端断开。
特点: 1)读锁:不影响所有客户端的读,但会阻止所有客户端的写。
如图加了读锁后,进行操作。
结果显示,加了读锁不会影响所有客户端的读,但是会阻塞客户端的写。
2)写锁:会阻塞其他客户端的读,又会阻塞 其他客户端的写。
如图加了写锁,进行操作。
结果显示:加了写锁不会影响本客户端的写和读,但其他客户端无法读写。
元数据锁(meta data lock,MDL) MDL加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上。MDL锁主要作用是维 护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML与 DDL冲突,保证读写的正确性。
这里的元数据,大家可以简单理解为就是一张表的表结构。 也就是说,某一张表涉及到未提交的事务 时,是不能够修改这张表的表结构的。
意向锁 为了避免DML在执行时,加的行锁与表锁的冲突,在InnoDB中引入了意向锁,使得表锁不用检查每行 数据是否加锁,使用意向锁来减少表锁的检查。
文章目录
前言
背景介绍
问题描述
分析排查
解决方案
总结归纳
前言 见《研发日记,Matlab/Simulink避坑指南(七)——数据溢出钳位Bug》
见《研发日记,Matlab/Simulink避坑指南(八)——else if分支结构Bug》
见《研发日记,Matlab/Simulink避坑指南(九)——可变数组应用Bug》
见《【研发日记】Matlab/Simulink避坑指南(十)——移位溢出Bug》
见《【研发日记】Matlab/Simulink避坑指南(十一)——Delay周期Bug》
背景介绍 最近在一个项目中,使用Simulink写一段嵌入式代码,功能是滚动输出一组0~7的序列,但是软件启动第一个周期输出的0,要做特殊处理改成输出1。乍一看感觉挺简单,想着直接用一个Initialize Function模块重写第一个周期的值就能搞定了,但是就这么一个小应用让我栽了跟头,在整个工程中排查了几个小时才找到问题。下面就来分享一下这一小段个人经历。
一开始的模型搭建大概是下面这个样子:
Counter Write设置的优先级最高,Read设置的优先级最低,确保第一个周期的Counter值能被Initialize Function模块重写。
问题描述 按照上述示例,预想应该可以正常运行,但是实际运行时却跟预想的不一样,示例如下:
希望看到的是第一个周期输出1,但是看到的运行结果仍是0。
分析排查 使用前段时间解锁的Debug技能《【研发日记】Matlab/Simulink技能解锁(四)——在Simulink Debugger窗口调试》,来调试一下上述模型,示例如下:
按Block步进执行,并输出Data Value,可以看到Initialize Function模块是在进入主循环之前就已经执行完了,所以才没有在第一个周期里重写Counter值。
这时候我们把模型生成C代码,来进一步确认实际执行顺序是否如上面Debuger窗口所示,示例如下:
#include <stddef.h> #include <stdio.h> /* This ert_main.c example uses printf/fflush */ #include "InitializeFunctionBug.h" /* Model's header file */ #include "rtwtypes.h" /* * The example "main" function illustrates what is required by your * application code to initialize, execute, and terminate the generated code.
目录
前言
一、全国风景区信息介绍
1、全国范围内数据分布
2、全国风景区分布
3、PostGIS空间关联查询
二、后台查询的设计与实现 1、Model和Mapper层
2、业务层和控制层设计
三、WebGIS可视化
1、省份范围可视化
2、省级风景区可视化展示 3、成果展示 总结 前言 旅行是心灵的洗涤,让每一步都充满感悟和思考。在旅途中,我学会了更加珍惜眼前的风景和时光。每一次旅行都是一次重新认识自己的机会,让我更加明白自己想要的是什么。旅途中的风景和经历,成为了我人生中最宝贵的财富。旅行让我感受到了世界的广阔和无限可能,让我更加勇敢地追求自己的梦想。在旅途中,我学会了用心去感受每一个细节,去品味生活的美好。旅行是一种生活方式,让我不断地探索和发现,不断地成长和进步。每一次旅行都是一次心灵的洗礼,让我更加清晰地认识自己和世界。旅途中的风景和经历成为了我人生中最珍贵的记忆,陪伴着我走过每一个春夏秋冬。旅行是一种自由和释放,让我在行走中找到自己的方向和目标。
不知道您是否还记得自己上一次旅行是在什么时候?是跟身边的谁一起去参加的旅行?在旅行中最令人难忘的风景是什么?除了风景还有什么让你印象深刻。身体和灵魂,总要有一个在路上。既然选择了在路上,那么我们就要去风景优美的地方看看,去美丽的景区游览,让身心得到放松,放松之后积蓄能量,为以后的生活持续奋斗。
各省风景区
不管是作为爱旅游的你,还是热爱文旅分析。使用WebGIS,我们来进行一场时空之旅,在地图上实现我们的地图旅行。本文以全国的旅游资源为例,分省份进行展示,将不同省份的风景区信息进行地图标注。我们也可以看一下全国范围内,风景区的时空分布。
本文即是在此背景下创作的,文章首先对数据库中的风景区数据进行简单介绍,然后介绍如何使SpringBoot进行风景区查询功能的设计与实现,接着介绍前端基于Leaflet进行可视化设计,最后使用实际应用,介绍和分析不同省份的风景区旅游资源。热爱旅游的你,一定不要错过,欣赏风景,让我们一起去看看吧。
一、全国风景区信息介绍 本节将对涉及的主要数据,即全国风景区信息进行简单介绍,其实在之前的一篇博客中,曾经对全国的风景区数据进行了详细的介绍,使用Java和PostGis的全国A级风景区数据入库实战。在这篇博客中,对全国A级风景区进行了入库的实践。
1、全国范围内数据分布 在之前的博客中,我们已经实现了数据的入库,为了避免让读者引起唐突的感觉,这里首先将数据表结构再次进行介绍,让读者熟悉和掌握对空间表的设计与实现。
对应的表结构脚本如下:
CREATE TABLE "public"."biz_scenic_spot" ( "id" int8 NOT NULL, "name" varchar(255) COLLATE "pg_catalog"."default", "level" varchar(4) COLLATE "pg_catalog"."default", "province" varchar(255) COLLATE "pg_catalog"."default", "city" varchar(255) COLLATE "pg_catalog"."default", "area" varchar(255) COLLATE "pg_catalog"."default", "address" varchar(255) COLLATE "pg_catalog"."default", "evaluation_time" varchar(255) COLLATE "pg_catalog"."default", "publish_time" varchar(255) COLLATE "pg_catalog"."default", "lng_gcj02" varchar(30) COLLATE "pg_catalog"."default", "
前言
📫 大家好,我是南木元元,热爱技术和分享,欢迎大家交流,一起学习进步!
🍅 个人主页:南木元元
目录
事件循环概述
异步和单线程
同步任务
异步任务
任务队列
宏任务
微任务
例题
示例1
示例2 示例3 示例4 结语
事件循环概述 JavaScript是一种单线程语言,事件循环(Event Loop)作为JavaScript的核心执行机制,可以有效地进行异步处理,保证用户界面的响应性和流畅性。
事件循环的工作流程如下:
所有同步任务都在主线程上执行,形成一个执行栈在执行同步任务的时候,如果遇到了异步事件,会将该任务挂起,继续执行同步任务,当异步事件执行完后(如定时器到时,ajax请求返回),再将对应的回调加入到一个任务队列中等待执行,任务队列分为宏任务队列和微任务队列当执行栈中的同步任务执行完毕后,会执行所有微任务,清空微任务队列当执行完所有微任务后,再去执行宏任务队列中的下一个宏任务,不断循环,直到所有任务都完成。 异步和单线程 JavaScript 最初被设计为一门单线程语言,是因为它的主要用途是与用户的交互以及操作DOM。为了避免同一时间对同一个DOM元素进行操作从而导致不可预知的问题,JavaScript从一诞生就是单线程,避免了多线程环境中的复杂同步问题。
单线程的意思是在任何给定时间内,只能执行一个任务。这也意味着 JavaScript 代码执行可能面临阻塞问题,即一个耗时操作(如大量计算或高延迟的 I/O 操作)会阻塞整个程序的运行,如果代码阻塞只能一直等下去,这样导致很差的用户体验。所以事件循环的出现让 js 拥有异步的能力。
同步任务 同步任务指的是在主线程上直接执行的任务,按照代码顺序依次执行,其执行会阻塞后续代码的运行,直到任务完成。
console.log('开始执行'); // 同步任务 function doSomething() { console.log('这是一个同步任务'); } doSomething(); // 调用同步函数 console.log('结束执行'); //开始执行 //这是一个同步任务 //结束执行 在这个示例中, doSomething()函数的调用是同步的,因此它会立即执行,并且后续代码必须等待它执行完成才能继续。
异步任务 异步任务是在主线程执行的同时,通过回调函数等机制委托给其他线程或事件来处理的任务,它不会立即执行,而是在将来的某个时刻完成。在执行异步任务时,主线程不会等待任务完成,而是继续执行后续代码。
异步执行的机制使得 JavaScript 能够更好地处理耗时操作,保持页面的响应性。
console.log('开始执行'); // 异步任务 setTimeout(() => { console.log('这是一个异步任务'); }, 1000); // 延迟1秒后执行 console.
我是娜姐 @迪娜学姐 ,一个SCI医学期刊编辑,探索用AI工具提效论文写作和发表。
这篇先介绍10款AI 检测工具,改天继续写AI检测的原理及如何降低AI率。欢迎持续关注。
先声明,直接用AI生成论文不可取,ChatGPT最好的用法是帮我们搭论文框架,润色。好工具用得好才能威力无穷。
1 GPTZero,推荐指数5/5颗星
获得方式: https://gptzero.me/
推荐理由:我用了发表在NEJM上的一篇论文来测试对比。先用标题让ChatGPT生成一篇300字左右的摘要(挺像那么回事的)。然后分别丢进GPTZero,结果显示ChatGPT生成的是“written by AI”,而原作者的是“written by a human”。还挺准的。它还可以选择上传整个文件。免费,免注册就能用。
2 CheckforAI,推荐指数4/5颗星
获得方式:https://checkforai.com/beta/
推荐理由:它的检测结果更详细。可以按照句子,给出不同程度的相似度打分。有点像crosscheck的相似度检测。需注册,免费。也可以上传文档。
3 Sapling,推荐指数3/5颗星
获得方式:https://sapling.ai/ai-content-detector
推荐理由:据说是有前斯坦福、谷歌研究人员开发的。免费可检测2000字,注册可达8000字。但是,这个查出来AI写作比例只有22.7%,哈哈,AI骗过了AI. 但是,原作者的文字Fake是0.
4 StudyCorgi,推荐指数4/5颗星
获取方式:https://studycorgi.com/free-writing-tools/chat-gpt-detector/
推荐理由:可给出详细的具体到单词的AI生成可能性报告。为了方便学生写essay的,主要是为了让学生使用他们的人工改写业务。一次可输入4500单词,结果比较准确。
5 Winston AI,推荐指数2/5颗星
获取方式:https://gowinston.ai/
推荐理由:可以给打分,还有详细报告,哪些句子是AI生成的。需要邮箱注册,有2000单词的免费额度,用完就要按月付费。
6 Crossplag AI Content Detector,推荐指数4/5颗星
获取方式:https://crossplag.com/ai-content-detector/
推荐理由:免费,且无需注册。粘贴内容,点击“Check”,速度很快,直接给出了一个83%“该文本主要由AI生成”的结论。准确。
7 WriteCream AI Content Detector,推荐指数2/5颗星
获取方式:https://www.writecream.com/ai-content-detector/
推荐理由:无需注册,免费使用。可以给出具体的AI内容百分比。但是,貌似结果不准确,打出了34%分。
8 Copyleaks AI Content Detector,推荐指数2/5颗星
获取方式:https://copyleaks.com/ai-content-detector 推荐理由:会给高度可疑的句子标红。没有评分。免费,无需注册直接使用。但是结果不太准确。
9 OpenAI's AI Text Classifier,推荐指数3/5颗星
获取方式:https://platform.openai.com/ai-text-classifier
推荐理由:openai公司自己出的AI 生成内容检测工具。哈哈,这是既当裁判又当运动员。对于ChatGPT生成的内容,它的检测结果是“unclear if it is AI-generated",原作者的摘要则是”very unlikely AI-generated“。emm。。。需要openai的账号登录,免费的。
欢迎来到《小5讲堂》
这是《Python》系列文章,每篇文章将以博主理解的角度展开讲解。
温馨提示:博主能力有限,理解水平有限,若有不对之处望指正!
目录 前言无执行文件代码报错信息错误路径手动下载自动下载 选项配置Chrome入参Selenium介绍文章推荐 前言 有时候我们需要爬取一些数据进行分析和测试,
对于Python而言,selenium插件是爬虫最佳选择,
本篇文章将简单列一些常见错误和解决方法。
温馨提示,合理使用爬虫,任何技术都有利有弊,适当就好。
无执行文件 代码 import time from selenium import webdriver url = 'https://blog.csdn.net/gg_61024956/article/details/138566685?spm=1001.2014.3001.5501' driver = webdriver.Edge() driver.get(url) time.sleep(2) comment_button = driver.find_element(by=By.ID,value='comment_content') print(comment_button.text) 报错信息 Message: ‘chromedriver’ executable needs to be in PATH. Pleasesee https://chromedriver.chromium.org/home
消息:“chromedriver”可执行文件需要在PATH中。Pleasesehttps://chromedriver.chromium.org/home
错误路径 很多小伙伴会以为是这个路径,发现是可以运行的,可以自动打开浏览器,但并不能控制浏览器
手动下载 手动下载ChromeDriver(建议使用自动下载模式,简单方便省事)
可以手动下载ChromeDriver并将其放置在一个你容易访问的地方,比如你的项目文件夹中。
ChromeDriver官方地址:https://chromedriver.chromium.org/downloads
自动下载 自动下载ChromeDriver,自动下载并安装与当前系统中已安装的 Chrome 浏览器版本相匹配的 ChromeDriver。这样做的好处是,你无需手动去下载和管理 ChromeDriver 的版本,而是让
webdriver_manager 库来处理这个任务,确保你使用的 ChromeDriver 版本与 Chrome 浏览器版本兼容。
先安装,pip install webdriver_manager
from webdriver_manager.chrome import ChromeDriverManager driver = webdriver.
财务管理系统
目录
基于SprinBoot+vue的财务管理系统
一、前言
二、系统设计
三、系统功能设计 系统功能实现
1管理员功能模块
2员工功能模块
四、数据库设计
五、核心代码 六、论文参考
七、最新计算机毕设选题推荐
八、源码获取:
博主介绍:✌️大厂码农|毕设布道师,阿里云开发社区乘风者计划专家博主,CSDN平台Java领域优质创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。✌️
主要项目:小程序、SpringBoot、SSM、Vue、Html、Jsp、Nodejs等设计与开发。
🍅文末获取源码联系🍅
基于SprinBoot+vue的财务管理系统 一、前言 本文首先介绍了财务管理技术的发展背景与发展现状,然后遵循软件常规开发流程,首先针对系统选取适用的语言和开发平台,根据需求分析制定模块并设计数据库结构,再根据系统总体功能模块的设计绘制系统的功能模块图,流程图以及E-R图。然后,设计框架并根据设计的框架编写代码以实现系统的各个功能模块。最后,对初步完成的系统进行测试,主要是功能测试、单元测试和性能测试。测试结果表明,该系统能够实现所需的功能,运行状况尚可并无明显缺点。
关键字:财务管理;springboot;Mysql数据库
二、系统设计 系统功能结构如图
三、系统功能设计 系统功能实现 系统登录,管理员和员工进入系统前在登录页面根据要求填写用户名和密码,选择角色等信息,点击登录进行登录操作,如图5-1所示。
图5-1系统登录界面图
1管理员功能模块 管理员登录系统后,可以对首页,个人中心,员工管理,部门管理,员工工资管理,工资调整管理,资产类别管理,固定资产管理,经营信息管理,序时账管理,年度利润管理,系统管理等功能进行相应的操作管理,如图5-2所示。
图5-2管理员功能界面图
2员工功能模块 员工登录进入系统可以对首页,个人中心,员工工资管理,工资调整管理,系统管理等功能进行相应操作,如图5-12所示。
图5-12员工功能界面图
四、数据库设计 (1)员工管理E/R图如下所示:
图4-2员工管理E/R图
表4-1:序时账
字段名称
类型
长度
字段说明
主键
默认值
id
bigint
主键
主键
addtime
timestamp
创建时间
CURRENT_TIMESTAMP
pingzhengdanhao
varchar
200
凭证单号
fapiao
varchar
200
发票
shouzhileixing
varchar
200
收支类型
zhaiyao
varchar
200
摘要
duifangkemu
varchar