【C++】透析类和对象(上)

有不懂的,可翻阅我之前文章哦! 个人主页:CSDN_小八哥向前冲 所属专栏:C++入门 目录 类的定义 访问限定符 类域 类的实例化 实例化概念 对象大小 this指针 类的默认成员函数 构造函数 析构函数 模拟栈(初学者) 类的定义 class为定义类的关键字,Stack为类的名字,{}中为类的主体,注意类定义结束时后⾯分号不能省 略。类体中内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的⽅法或 者成员函数。C++中struct也可以定义类,C++兼容C中struct的⽤法,同时struct升级成了类,明显的变化是 struct中可以定义函数,⼀般情况下我们还是推荐⽤class定义类。定义在类⾯的成员函数默认为inline。 问题:struct和class都可以定义类,那有什么区别呢? 既然开始学习C++了,不要老想着用C语言的那一套,在C语言中,Struct是用来定义结构体的,容易混,虽然C++兼容C,但是在一定程度上会混淆自己!Struct在没有添加访问限定符时,默认为public,而class默认为private。 访问限定符 public修饰的成员在类外可以直接被访问;protected和private修饰的成员在类外不能直接被访问,它们俩的区别,我们现在不做深究!⼀般成员变量都会被限制为private/protected,需要给别⼈使⽤的成员函数会放为public。 类域 类定义了⼀个新的作⽤域,类的所有成员都在类的作⽤域中,在类体外定义成员时,需要使⽤::作⽤域操作符指明成员属于哪个类域。 类的实例化 实例化概念 ⽤类类型在物理内存中创建对象的过程,称为类实例化出对象。类是对象进⾏⼀种抽象描述,是⼀个模型⼀样的东西,限定了类有哪些成员变量,这些成员变量只是声明,没有分配空间,⽤类实例化出对象时,才会分配空间。⼀个类可以实例化出多个对象,实例化出的对象 占⽤实际的物理空间,存储类成员变量。打个⽐⽅:类实例化出对象就像现实中使⽤建筑设计图建造出房⼦,类就像是设计图,设计图规划了有多 少个房间,房间⼤⼩功能等,但是并没有实体的建筑存在,也不能住⼈,⽤设计图修建出房⼦,房 ⼦才能住⼈。同样类就像设计图⼀样,不能存储数据,实例化出的对象分配物理内存存储数据。 上图理解: 总结理解: 定义一个类的过程中,只是起到了声明作用,并没有开辟空间占用内存,当实例化出一个对象来,这才开辟了一块内存! 对象大小 开辟出一个空间来,那这个空间大小是多少呢? 简单来说,它的空间占用情况和C语言里面的结构体一模一样!也就是说我们计算一个对象大小也就是算C语言里面的结构体大小! 如果忘了C语言中结构体计算可以去这篇文章:结构体和联合体的计算_小八哥向前冲 我们来一起复习一下: 第⼀个成员在与结构体偏移量为0的地址处。其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。注意:对⻬数=编译器默认的⼀个对⻬数与该成员⼤⼩的较⼩值。VS中默认的对⻬数为8。结构体总⼤⼩为:最⼤对⻬数(所有变量类型最⼤者与默认对⻬参数取最⼩)的整数倍。如果嵌套了结构体的情况,嵌套的结构体对⻬到⾃⼰的最⼤对⻬数的整数倍处,结构体的整体⼤⼩ 就是所有最⼤对⻬数(含嵌套结构体的对⻬数)的整数倍。 那如果没有成员只有函数呢? 这里放1的原因: 为什么没有成员变量还要给1个字节呢?因为如果⼀个字节都不给,怎么表⽰对象存在过呢!所以这⾥给1字节,纯粹是为了占位标识对象存在。 this指针 Date类中有Init与Print两个成员函数,函数体中没有关于不同对象的区分,那当d1调⽤Init和 Print函数时,该函数是如何知道应该访问的是d1对象还是d2对象呢?那么这⾥就要看到C++给了 ⼀个隐含的this指针解决这⾥的问题。C++规定不能在实参和形参的位置显⽰的写this指针(编译时编译器会处理),但是可以在函数体内显 ⽰使⽤this指针。 this指针方便更好地指向当前对象!调用类里面的函数,函数前面会隐含this指针,但是不能自己添加,但可以在函数里面调用this指针! 图理解: 类的默认成员函数 默认成员函数就是⽤⼾没有显式实现,编译器会⾃动⽣成的成员函数称为默认成员函数。 ⼀个类,我 们不写的情况下编译器会默认⽣成以下6个默认成员函数。 那编译器自己会生成,是不是就不用我们自己写了?其实不然! 我们写不写需要看俩个方面: 第⼀:我们不写时,编译器默认⽣成的函数⾏为是什么,是否满⾜我们的需求。第⼆:编译器默认⽣成的函数不满⾜我们的需求,我们需要⾃⼰实现。 构造函数 构造函数的特点: 函数名与类名相同。⽆返回值。(返回值啥都不需要给,也不需要写void,不要纠结,C++规定如此)。对象实例化时系统会⾃动调⽤对应的构造函数。构造函数可以重载。如果类中没有显式定义构造函数,则C++编译器会⾃动⽣成⼀个⽆参的默认构造函数,⼀旦⽤⼾显 式定义编译器将不再⽣成。⽆参构造函数、全缺省构造函数、我们不写构造时编译器默认⽣成的构造函数,都叫做默认构造函 数。但是这三个函数有且只有⼀个存在,不能同时存在。⽆参构造函数和全缺省构造函数虽然构成 函数重载,但是调⽤时会存在歧义。要注意很多同学会认为默认构造函数是编译器默认⽣成那个叫 默认构造,实际上⽆参构造函数、全缺省构造函数也是默认构造,总结⼀下就是不传实参就可以调 ⽤的构造就叫默认构造。我们不写,编译器默认⽣成的构造,对内置类型成员变量的初始化没有要求,也就是说是是否初始 化是不确定的,看编译器。 图:

Hive基础知识大全

Hive基础知识大全 文章目录 Hive基础知识大全1、Hive基本概念1.1、Hive简介1.2、什么是Hive(面试题)1.3、为什么要使用Hive1.4、Hive的特点1.5、Hive的优缺点1.6、hive和mysql的区别1.7、hive的应用场景1.8、Hive架构1.8.1、Hive Client1.8.2、Hive Metastore(Hive的元数据存储)1.8.3、**sql语句是如何转换成MapReduce任务的**(重点!!!!!!!!!!!!) 2、Hive的三种交互方式(1) 第一种交互方式(2) 第二种交互方式(3) 第三种交互方式(4) hive cli和beeline cli的区别 3、Hive元数据4、Hive的基本操作4.1 Hive库操作4.1.1 创建数据库4.1.2 创建数据库和位置4.1.3 修改数据库4.1.4 数据库详细信息4.1.5 删除数据库(将删除的目录移动到回收站中) 4.2、Hive数据类型4.2.1、基础数据类型4.2.2、复杂数据类型 4.3、Hive表操作4.3.1、创建表建表1:创建内部表(全部使用默认建表方式)建表2:创建外部表建表3:指定存储格式建表4:使用查询语句建表 (这种方式比较常用)建表5:只想建表,不需要加载数据 4.3.2、加载数据1、使用```hdfs dfs -put '本地数据' 'hive表对应的HDFS目录下'```2、使用 load data3、create table xxx as SQL语句4、insert into table xxxx SQL语句 (没有as) 4.3.3、对表进行修改4.3.4、工作案例第一步:在hdfs上创建表数据存储的文件夹第二步:将数据上传到hdfs上第三步:创建表 4.3.5、Hive导出数据 Hive分区与排序(内置函数)1、Hive分区(十分重要!!)1.1 静态分区(SP)1.3 动态分区(DP) 2、Hive分桶2.1 业务场景数据分桶的适用场景: 2.2 数据分桶原理2.3 数据分桶优势2.4 分桶实战 3、Hive JDBC启动hiveserver2新建maven项目并添加两个依赖编写JDBC代码 4、Hive的4种排序4.1 全局排序4.2 局部排序(对reduce内部做排序)4.3 分区排序(本身没有排序)4.3 分区并排序 5、Hive内置函数5.1 内置函数分类5.2 UDTF hive中特殊的一个功能(进一出多)5.3 WordCount案例 Hive函数学习1、count(*)、count(1) 、count('字段名') 区别2、**hive语句的执行顺序**3、Hive 常用函数3.1、关系运算3.2、数值计算3.3、条件函数(主要使用场景是数据清洗的过程中使用,有些构建表的过程也是需要的)3.4、日期函数重点!!!3.5、字符串函数3.6、例题:Hive 中的wordCount3.7、Hive窗口函数3.7.1、 聚合开窗函数聚合开窗函数实战:实战1:Hive用户购买明细数据分析实战1需求: 3.7.2、 排序开窗函数(重点)实战2:Hive分析学生成绩信息 4、Hive 行转列5、Hive 列转行6、Hive自定义函数UserDefineFunction6.

奇怪的Excel单元格字体颜色格式

使用VBA代码修改单元格全部字符字体颜色是个很简单的任务,例如设置A1单元格字体颜色为红色。 Range("A1").Font.Color = RGB(255, 0, 0) 有时需要修改部分字符的颜色,如下图所示,将红色字符字体颜色修改为蓝色。代码将会稍许复杂,需要使用Characters设置逐个字符的字体颜色。 先使用代码来读取单元格的字体颜色。 Sub CheckFontColor() Dim c As Range, i As Long Set c = Range("A1") For i = 1 To Len(c.Value) With c.Characters(i, 1).Font Debug.Print i, .Color End With Next End Sub 输出如下所示,前5个字符和最后两个字符为红色。 1 255 2 255 3 255 4 255 5 255 6 0 7 0 8 255 9 255 略加修改,逐个字符判断字体颜色,修改红色字符为蓝色。 Sub ChangeColor1() Dim c As Range, i As Long, ColS As Long, ColE As Long Range("

{Spring Boot 原理篇} Spring Boot自动装配原理

@SpringBootApplication 1,Spring Boot 应用启动,@SpringBootApplication标注的类就是启动类,它去实现配置类中的Bean的自动装配 @SpringBootApplication public class SpringbootRedis01Application { public static void main(String[] args) { SpringApplication.run(SpringbootRedis01Application.class, args); } } 2,而@SpringBootApplicatiozn注解中包含了三个注解: @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited //以上四个都为元注解,以下三个才是去实现自动装配的注解 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) @SpringBootConfiguration 这个注解包含了@Configuration,@Configuration里面又包含了一个@Component注解,也就是 说,这个注解标注在哪个类上,就表示当前这个类是一个配置类,而配置类也是spring容器中的组 件, @SpringBootConfiguration:对@Configuration 注解的封装,标注当前类是配置类,并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中。 @EnableAutoConfiguration 这个注解是开启自动配置的功能核心注解,里面包含了两个注解 @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) @AutoConfigurationPackage: 将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器,这也就是为什么我们在利用springboot进行开发的时候,无论是Controller还是Service的路径都是与主配置类同级或者次级的原因。 @Import(AutoConfigurationImportSelector.class) 上一个注解我们把所有组件都加载到了容器里面,这个注解就是将需要自动装配的类以全类名的方 式返回 1、AutoConfigurationImportSelector这个类里面有一个方法selectImports(),如下 2、在selectImport()方法里调用了一个getAutoConfigurationEntry()方法,这个方法里面又调用 了一个getCandidateConfigurations()方法 3、在getCandidateConfigurations()方法里面调用了loadFactoryNames()方法、

扫雷-C语言

一、前言: 众所周知,扫雷是一款大众类的益智小游戏,它的游戏目标是在最短的时间内根据点击格子出现的数字找出所有非雷格子,同时避免踩雷,踩到一个雷即全盘皆输。 今天,我们的目的就是通过C语言来实现一个简单扫雷游戏。 主要操作有: 1.初始化棋盘; 2.打印棋盘; 3.统计周围雷的个数; 4.排雷; 5.判断输赢; 我这里是通过三个文件:源文件(Test.c)源文件(Game.c)头文件(Game.h)来实现的它们分别有各自的分工: 1.源文件-Test.c:主要用于调用定义的函数来实现扫雷操作。 2.源文件-Game.c:主要用于定义头文件-Game.h声明的函数。 3.头文件-Game.h:主要用于声明所需要的操作的函数。 二、头文件-Game.h: 2.1-目的: 这里我们需要的操作是声明所需要的头文件,将所需要的操作声明成一个函数并在源文件-Game.c中定义所声明的函数。 2.2-代码: #pragma once #include <stdio.h> #include <stdlib.h> #include <time.h> #define ROW 9 #define COL 9 #define ROWS 11 #define COLS 11 #define COUNT 10 //选单 void menu(); //扫雷游戏 //用于整理函数,实现扫雷所有操作 void game(); //初始化棋盘 void InitBoard(char board[ROWS][COLS],int rows,int cols,char tem); //打印棋盘 void PrintBoard(char board[ROWS][COLS], int row, int col); //布置雷 void SetBoard(char board[ROWS][COLS], int row, int col); //排除雷 void FindBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col); //统计周围雷的个数 int get_mine_count(char mine[ROWS][COLS],int x,int y); //判断是否获胜 int If_win(int win); 三、源文件-Game.

091、Python 写Excel文件(使用openpyxl库)

要写Excel文件,我们需要使用第三方库。 xlwt库是一个常用的写Excel的第三方库,它主要支持低版本(xls)的Excel写文件,要写高版本(xlsx),则需要用另外一个库:openpyxl 要使用该第三方库,首先需安装: pip install openpyxl 安装完成后,我们就可以引入库来进行相关操作了。 使用openpyxl库写Excel文本,可以按以下步骤操作: 1、第一步:创建工作簿(Workbook): wb = openpyxl.Workbook() 2、第二步:添加工作表(Worksheet): sheet = wb.create_sheet('期末成绩') 3、第三步:设置单元格样式: # 字体样式 font = Font(name='Arial', size=11, bold=True, italic=False, vertAlign=None, underline='none', strike=False, color="FF0000") # 红色 # 边框样式 thin = Side(border_style="thin", color="000000") border = Border(left=thin, top=thin, right=thin, bottom=thin) # 背景色 fill = PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid") # 对齐样式 alignment = Alignment(horizontal="center", vertical="center") 4、第四步:向单元格写入数据: titles = ('姓名', '语文', '数学', '英语') for col_index, title in enumerate(titles): cell = sheet.

WebKit的图像魔法:深入CSS Image Values支持

WebKit的图像魔法:深入CSS Image Values支持 CSS图像值(Image Values)是CSS3中引入的一系列新特性,它们为Web开发者提供了更多的灵活性和创造力来处理网页上的图像。WebKit作为许多流行浏览器的底层引擎,其对CSS图像值的支持情况直接影响着这些特性的实用性和普及度。本文将深入探讨WebKit对CSS图像值的支持,并提供实际的代码示例。 一、CSS图像值简介 CSS图像值是指在CSS中用于图像处理的各种属性和函数,包括但不限于: background-imageborder-imagelinear-gradient()radial-gradient()image-set()cross-fade() 这些属性和函数允许开发者在不同的上下文中以不同的方式使用图像,从而创建丰富和动态的视觉效果。 二、WebKit对CSS图像值的支持 截至2024年,WebKit对CSS图像值的支持已经相当全面,包括对渐变、图像集、交叉渐变等特性的支持。然而,由于WebKit是一个活跃的开源项目,其支持的具体特性和版本可能会随时间而变化。 三、使用CSS图像值 以下是一些CSS图像值的使用示例: 线性渐变: div { background-image: linear-gradient(to right, blue, red); } 径向渐变: div { background-image: radial-gradient(circle, yellow, orange); } 图像集: img { background-image: image-set( 'small.jpg' 500w, 'medium.jpg' 1000w, 'large.jpg' 2000w ); } 交叉渐变: div { background-image: cross-fade('img1.png', 'img2.png', 0.5); } 四、响应式图像 image-set()函数是CSS图像值中一个重要的特性,它允许开发者为不同分辨率的显示设备提供不同大小的图像,以优化加载时间和性能。 img { width: 100%; height: auto; background-image: image-set( 'small.jpg' 1x, 'medium.jpg' 2x ); } 在这个例子中,浏览器会根据设备的分辨率选择适当的图像。 五、浏览器兼容性 虽然WebKit对CSS图像值的支持良好,但不同浏览器和不同版本的WebKit可能存在兼容性差异。开发者在使用时应检查Can I use以获取最新的兼容性信息。

探索WebKit的WebUSB API:开启浏览器与硬件的无缝对话

探索WebKit的WebUSB API:开启浏览器与硬件的无缝对话 在当今技术日益融合的时代,浏览器已成为连接用户与各种硬件设备的重要桥梁。WebKit的WebUSB API为Web开发者提供了一种新的方式,允许网页直接与USB设备进行通信,无需安装任何插件或扩展。这一功能极大地扩展了Web应用的潜力,从简单的数据传输到复杂的硬件控制,都可以通过浏览器实现。本文将详细介绍WebKit的WebUSB API,并提供实际的代码示例。 一、WebUSB API简介 WebUSB API是一种允许Web页面与USB设备进行通信的Web标准,它提供了一种简单、安全的方法来访问连接到用户计算机的USB设备。通过WebUSB,开发者可以创建能够与各种硬件设备交互的Web应用。 二、WebKit对WebUSB API的支持 截至2024年,WebKit已经在其浏览器中对WebUSB API提供了实验性支持。这意味着在基于WebKit的浏览器(如Safari)中,开发者可以开始尝试使用这项技术。然而,由于这是一项相对较新的技术,可能还需要一些时间才能在所有浏览器中得到广泛支持。 三、基本语法和流程 使用WebUSB API的基本流程如下: 检查浏览器支持:首先需要检查浏览器是否支持WebUSB API。 if ('navigator' in window && 'usb' in navigator) { console.log('WebUSB is supported!'); } else { console.log('WebUSB is not supported in this browser.'); } 请求设备:通过navigator.usb.requestDevice方法请求访问用户设备。 async function requestDevice() { try { const device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x1234, productId: 0x5678 }] }); console.log('Device connected:', device); return device; } catch (error) { console.

【数据结构】二叉树———Lesson2

Hi~!这里是奋斗的小羊,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~ 💥💥个人主页:奋斗的小羊 💥💥所属专栏:数据结构 🚀本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为记录我的学习过程及理解。文笔、排版拙劣,望见谅。 目录 前言一、TOP-K问题二、二叉树的链式结构2.1前中后序遍历2.2节点个数2.3叶子个数2.4高度 / 深度2.5第K层节点数2.6查找值为x的节点2.7二叉树销毁2.8相关OJ题2.9层序遍历 总结 前言 在TOP-K问题中有一种方法能在占用很小空间的情况下高效地找出最大或最小的前K个数。 在上篇文章介绍树时说树是递归定义的,因此二叉树的遍历、二叉树的搜索、二叉树的深度、高度、节点数、二叉树的路径求解等问题,基本都会用递归解决。 一、TOP-K问题 接上篇文章,我们简单地了解了TOP-K问题,介绍了如何从比较大的数据量中快速找出最大(最小)的前K个数据。 | 方法一: 用这些较大的数据量建堆,循环Top、Pop,找出最大(最小)的前K个数。 但是这个方法有个致命缺陷,它只适合数据量还不是特别大的情况,因为如果数据量非常大时我们还建堆的话,这对空间的消耗是很大的,那我们就要想别的办法了。如果数据海量,但我们现在只有1GB的内存,直接建堆显然行不通。 | 方法二: 将这海量数据分成合适的若干份分别建堆,找出每份中的最大(最小)的前K的数,再将这些数建堆,循环Top、Pop K次就能找到最大(最小)的前K个数。 但是这个方法也不是特别好,因为1GB的内存还是比较大的,假如这个问题非要搞我们,它有海量的数据但是只给我们1KB的内存,甚至更狠一点只给我们100Byte的空间,这时候方法二就显得力不从心了,因为这个若干份将会非常大,非常不理想。 | 方法三: 先从这海量数据中拿出前K个数建小堆(大堆),然后再不断拿出剩下的数和堆顶数据比较,如果大(小)于堆顶就替换掉堆顶,再向下调整保证堆成立,当这海量的数据全都比完后,留在堆内的数就是这海量数据中最大(最小)的前K个数。 这个方法需要注意的是如果要求我们找最大的前K个数要建小堆,最小的前K个数要建大堆。当然K也不能太大,要是我们现在可用的内存连这K个数都装不下那就有点扯淡了。 方法三代码如下: void test1() { FILE* pf = fopen("data.txt", "w"); if (pf == NULL) { perror("fopen fail"); return; } //产生随机的100000个数存到磁盘中 for (int i = 0; i < 100000; i++) { //rand函数产生的随机数有重复,+i减少重复的数 int ret = rand() + i; fprintf(pf, "%d\n", ret); } fclose(pf); pf = NULL; } void test2() { FILE* pf = fopen("

【C++】红黑树的全面探索和深度解析

✨ 慢品人间烟火色,闲观万事岁月长 🌏 📃个人主页:island1314 🔥个人专栏:C++学习 🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏 💞 💞 💞 1. 红黑树的概念 📒红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的 📙红黑树由Rudolf Bayer在1972年发明,最初被称为平衡二叉B树(Symmetric Binary B-trees),后来被Guibas和Robert Sedgewick修改为如今的“红黑树”。 2. 红黑树的性质 节点是红色或黑色:每个节点都有一个颜色属性,颜色可以是红色或黑色。 根节点是黑色:树的根节点必须是黑色。 红色节点的子节点是黑色:如果一个节点是红色,则它的两个子节点必须是黑色(即不能有两个连续的红色节点)。 每个节点到其每个叶子节点的路径都包含相同数量的黑色节点:从任何节点到其每个叶子节点的路径上,经过的黑色节点的数量必须相同。 叶子节点是黑色:红黑树的叶子节点(通常是指空节点)被视为黑色。 3. 红黑树的节点结构及定义 红黑树节点的定义通常包含以下几个关键部分: 🧩3.1 基本元素 _left:指向节点的左子节点的指针_right:指向节点的右子节点的指针_parent:指向节点的父节点的指针_kv:一个结构体或配对(pair),包含节点的键值(key)和值(value)。这取决于红黑的具体用途,可能只包含键或包含键值对。_col:表示当前节点的颜色。 🧩3.2 节点颜色(_col) 在上面的定义中,_col 成员变量用于表示节点的颜色,通过 Color 枚举类型来定义,可以是 RED 或 BLACK。 🧩3.3 构造函数 初始化一个新节点时,通常需要一个构造函数,它接受一个键值对(或仅键),并设置节点的左子节点、右子节点、父节点和颜色(初始化为红色) 🧩3.4 BR节点定义: template<class K, class V> struct BSTreeNode { BSTreeNode<K, V>* _left; //左子树 BSTreeNode<K, V>* _right; //右子树 BSTreeNode<K, V>* _parent; //父亲 pair<K, V> _kv; //存放节点值的 string _col; //颜色(通过这个可以直到左右子树存在情况) //构造函数 BSTreeNode(const pair<K, V>& kv) :_left(nullptr) , _right(nullptr) , _parent(nullptr) , _kv(kv) , _col("

卡夫卡(Kafka)框架详解:从背景到应用实践

卡夫卡(Kafka)框架详解:从背景到应用实践 引言 在大数据和分布式系统日益普及的今天,数据处理和消息传递成为了支撑复杂业务系统的关键基础设施。Apache Kafka,作为一个高性能的分布式消息队列系统,因其高吞吐量、低延迟和可扩展性,成为了众多企业和开发者首选的消息传递解决方案。本文将从Kafka的诞生背景、基本概念、核心组件、数据读写机制以及应用场景等多个维度,全面解析Kafka框架,帮助读者深入理解并掌握这一强大的技术工具。 一、Kafka的诞生背景 1.1 业务需求驱动 在Kafka诞生之前,许多业务系统对于数据的分析主要基于对象分析,即将数据以对象的形式存储在数据库中。然而,随着业务的发展,系统需要更多地关注数据的变化过程,即从何时何地发生了什么事情。这种对数据流的需求促使了Kafka等流处理框架的出现。 1.2 从对象分析到流处理 传统的数据库存储方式难以高效地处理大规模数据流,因为它们往往将数据视为静态的对象集合。而Kafka通过有序地存储数据流,使得系统能够实时地捕捉、处理和响应数据的变化,从而满足复杂业务场景的需求。 二、Kafka的基本概念 2.1 Topic与Partition Topic:Kafka中的Topic是一个逻辑上的概念,代表了一类消息的集合。每个Topic都可以被划分为多个Partition,以实现并行处理和负载均衡。Partition:Partition是Kafka中物理上的存储单元,每个Partition都是一个有序的、不可变的消息序列。Kafka通过多Partition的设计,提高了系统的并行处理能力和容错性。 2.2 Producer与Consumer Producer:Producer是消息的生产者,负责将消息发送到Kafka的Topic中。Producer可以指定消息的Key和Value,Kafka会根据Key和分区策略将消息发送到指定的Partition。Consumer:Consumer是消息的消费者,负责从Kafka的Topic中读取消息并进行处理。Kafka支持多个Consumer同时消费同一个Topic,每个Consumer属于一个Consumer Group,组内Consumer共同分担消息的消费工作。 2.3 Broker与Cluster Broker:Broker是Kafka集群中的一个节点,负责存储和处理Kafka中的消息。每个Broker上都可以运行多个Partition的副本,以提高系统的可用性和容错性。Cluster:Cluster是由多个Broker组成的Kafka集群,提供了高可用性和可扩展性的消息传递服务。 三、Kafka的核心组件 3.1 Leader与Follower 在Kafka的每个Partition中,都会选举出一个Leader副本和多个Follower副本。Leader负责处理所有的读写请求,而Follower则负责同步Leader的数据,以提供数据的冗余备份。当Leader出现故障时,Kafka会自动从Follower中选举出新的Leader,以保证系统的可用性。 3.2 ISR与AR ISR(In-Sync Replicas):ISR集合包含了所有与Leader保持同步的Follower副本。只有当消息被ISR中的所有副本成功写入后,该消息才被视为已提交。AR(All Replicas):AR集合包含了Partition的所有副本,包括ISR中的副本和未与Leader保持同步的副本。 3.3 Zookeeper Kafka依赖于Zookeeper进行集群管理和配置信息的存储。Zookeeper负责维护Kafka集群的元数据,包括Topic和Partition的信息、Broker的状态、ISR和AR的列表等。通过Zookeeper,Kafka实现了高可用性和可扩展性的集群管理。 四、Kafka的数据读写机制 4.1 写入机制 当Producer发送消息到Kafka时,Kafka会将消息追加到指定的Partition的末尾。为了提高写入性能,Kafka采用了顺序写入磁盘的方式,避免了随机磁盘I/O的开销。同时,Kafka还通过Page Cache和操作系统级别的缓存机制,进一步加速了消息的写入过程。 4.2 读取机制 Consumer从Kafka读取消息时,可以从指定的Partition的任意位置开始读取。Kafka通过维护每个Consumer Group的偏移量(Offset),来记录每个Consumer的消费进度。当Consumer消费完一条消息后,它会更新自己的偏移量,以便下次从上次消费的位置继续读取消息。 五、Kafka的应用场景 5.1 日志收集 Kafka最初的设计目标之一就是作为分布式日志收集系统。通过将日志数据发送到Kafka,系统可以实时地收集、处理和存储大量的日志信息。这对于故障排查、性能监控和数据分析等场景非常有用。 5.2 消息系统 Kafka作为一个高性能的消息队列系统,可以替代传统的消息中间件,如RabbitMQ、ActiveMQ等。Kafka提供了更高的吞吐量和更低的延迟,使得它更适合处理大规模的消息传递场景。 5.3 流处理 Kafka与流处理框架(如Apache Spark Streaming、Apache Flink等)结合使用,可以实现对数据流的实时处理和分析。通过将数据流发送到Kafka,然后使用流处理框架从Kafka中读取数据进行处理,系统可以实时地响应数据的变化,为业务决策提供有力的支持。 5.4 用户行为分析 在电商、社交等互联网领域,用户行为分析是提升用户体验和精准营销的重要手段。通过将用户行为数据发送到Kafka,并使用实时分析系统对数据进行处理和分析,企业可以实时地了解用户的行为习惯和兴趣偏好,从而为用户提供更加个性化的服务和推荐。 六、Kafka的优势与挑战 6.1 优势 高吞吐量:Kafka支持每秒处理数百万条消息,满足大规模数据处理的需求。低延迟:Kafka的消息传递延迟可以达到毫秒级别,适用于对实时性要求较高的场景。可扩展性:Kafka集群可以轻松地通过增加Broker节点来扩展处理能力,满足不断增长的业务需求。容错性:Kafka通过多副本机制实现了数据的高可用性,即使部分节点出现故障,也不会影响系统的正常运行。 6.2 挑战 复杂性:Kafka的架构和配置相对复杂,需要一定的学习和实践才能熟练掌握。运维成本:随着集群规模的扩大,Kafka的运维成本也会相应增加,包括监控、备份、恢复等方面的工作。依赖Zookeeper:Kafka高度依赖Zookeeper进行集群管理和配置信息的存储,Zookeeper的稳定性和性能直接影响到Kafka的可用性和性能。 七、结论 Apache Kafka作为一个高性能、低延迟、可扩展的分布式消息队列系统,已经在众多企业和项目中得到了广泛的应用。通过深入理解Kafka的背景、基本概念、核心组件、数据读写机制以及应用场景等方面的知识,我们可以更好地掌握这一强大的技术工具,并在实际工作中发挥其最大的价值。无论是日志收集、消息传递、流处理还是用户行为分析等领域,Kafka都为我们提供了强大的支持和保障。

2024.7.24 作业

1.二叉树的创建、遍历自己实现一遍 bitree.h #ifndef BITREE_H #define BITREE_H #include <myhead.h> typedef char datatype; typedef struct Node { datatype data; struct Node *left_child; struct Node *right_child; }Node,*BiTreePtr; //创建二叉树 BiTreePtr tree_create(); //先序遍历 void prio_order(BiTreePtr B); //中序遍历 void in_order(BiTreePtr B); //后序遍历 void post_order(BiTreePtr B); #endif bitree.c #include "bitree.h" //创建二叉树 BiTreePtr tree_create() { char data = 0; scanf(" %c",&data); if( data=='#') { return NULL; } BiTreePtr p = (BiTreePtr)malloc(sizeof(Node)); if( NULL==p ) { printf("节点申请失败\n"); return NULL; } p->data = data; p->left_child = tree_create(); p->right_child = tree_create(); return p; } //先序遍历 void prio_order(BiTreePtr B) { if( NULL==B ) { return ; } printf("

视图,存储过程和触发器

目录 视图 创建视图: 视图的使用 查看库中所有的视图 删除视图 视图的作用: 存储过程: 为什么使用存储过程? 什么是存储过程? 存储过程的创建 创建一个最简单的存储过程 使用存储过程 删除存储过程 带参的存储过程 存储过程的缺陷 存储过程和函数的区别 面试题 分页 触发器 什么是触发器? 创建触发器 例子: 查看触发器 删除触发器 存储过程和触发器的区别: 视图 是从一个或者几个基本表(或视图)导出的表,它与基本表不同,是一个虚表 视图只能用来查询,不能做增删改(虚拟表) 创建视图: create view 视图名【view_xxx / v_xxx】 as 查询语句 create view v_stu_man as select * from student where ssex='男'; 视图的使用 select * from v_stu_man; 查看库中所有的视图 select * from information_schema.VIEWS WHERE table_schema = 'myshool'; 删除视图 drop view v_stu_man; 视图的作用: 简化查询重写格式化数据频繁访问数据库过滤数据 存储过程: 本质上是一个函数

Win11 操作(四)g502鼠标连接电脑不亮灯无反应

罗技鼠标连接电脑不亮灯无反应 前言 罗技技术💩中💩,贴吧技术神中神! 最近买了一个g502,结果买回来直接插上电脑连灯都不亮,问了一下客服。客服简单的让我换接口,又是下载ghub之类的,总之最后还是让我退货了。 满怀期待的把第二个g502 插上电脑结果灯还是不亮,还是没反应。于是我打开设备管理器,发现能识别g502但是驱动无法正常安装。我点击更新驱动又提示拒绝访问,如图。 解决办法 我在互联网的世界里疯狂搜寻解决办法,但是没有任何相关的信息,直到我在贴吧里找到了同样问题的帖子https://tieba.baidu.com/p/9003668213,试了试大佬的办法,果真能行。 step1 step2 step3 step4 弹出一下页面,即鼠标能够正常使用

【C++】set的使用

🔥个人主页: Forcible Bug Maker 🔥专栏: STL || C++ 目录 🌈前言🌈关于set🔥容量函数==empty====size== 🔥Modifiers==insert====erase====clear== 🔥Operations==find====count====lower_bound和upper_bound====equal_range== 🌈关于multiset🌈结语 🌈前言 本篇博客主要内容:STL库中set的介绍以及其用法的讲解。 set和map的底层结构是红黑树,而红黑树又是一种特殊的二叉搜索树(红黑树可以保持树的平衡)。而我们今天来学习什么是set,以及如何使用set这个容器。如果对二叉搜索树不了解,可以参考这篇:【数据结构进阶】二叉搜索树 🌈关于set set是按照一定次序存储元素的容器在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。set在底层是用二叉搜索树(红黑树)实现的。 🔥容量函数 empty 判断set对象是否为空。 #include<iostream> #include<set> using namespace std; int main() { set<int> se; cout << se.empty() << endl; se.insert(1); cout << se.empty() << endl; return 0; } size 返回set对象中的元素个数。 #include <iostream> #include <set> int main () { std::set<int> myints; std::cout << "0. size: " << myints.size() << '\n'; for (int i=0; i<10; ++i) myints.

【算法专题】双指针算法之LCR 179. 查找总价格为目标值的两个商品(力扣)

欢迎来到 CILMY23的博客 🏆本篇主题为:双指针算法之LCR 179. 查找总价格为目标值的两个商品(力扣) 🏆个人主页:CILMY23-CSDN博客 🏆系列专栏:Python | C++ | C语言 | 数据结构与算法 | 贪心算法 | Linux | 算法专题 | 代码训练营 🏆感谢观看,支持的可以给个一键三连,点赞收藏+评论。如果你觉得有帮助,还可以点点关注 题目: LCR 179. 查找总价格为目标值的两个商品 - 力扣(LeetCode) 购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况,返回任一结果即可。 示例: 一、题目解析 根据题目给出的信息一共有以下几点: 1.price数组中的数据是升序排列 2.在数组中找两个数求和 3.存在多种情况,返回任一结果即可 --->找一个结果就行 4.情况中可能没有结果 在之前的磨练里,这种要找两个数,并且求和的,它是需要两个指针,所以这题为双指针算法 二、算法原理 这题的解法跟之前的几篇写过的原理相似。 我们可以先想想暴力破解是如何做的: 这题双循环,然后给它记录下来,一个数一个数的遍历过去,这样暴力破解的思路大致清晰了。 因为存在多种情况,返回任一结果即可 --->找一个结果就行。 暴力破解的复杂度是O(n^2),我们可以采用双指针算法来减少空间复杂度达到O(n)。 解析: 我们让一个left指向第一个数,right指向第二个数,如果他们加起来和target 给的数相等,那么我们就返回这两个数。 假设 left + right < 18,那说明left太小了,可以增加left的值,因为数组是单调递增,所以先增加最小的值,故让left++。 假设 left + right > 18,那说明right太小了,可以增加right的值,因为数组是单调递增,所以先减小最大的值,故让right--。 那如果没有结果,我们就返回一个{}就可以了。 三、代码编写 class Solution { public: vector<int> twoSum(vector<int>& price, int target) { int left = 0; int right = price.

初阶数据结构——二叉树大汇总

这篇博客将会讲到二叉树的部分内容及堆的相关知识~ 这里将会涉及到大量的递归(头大) 目录 1.树 1.1树的概念 1.2树的相关概念 1.3树的表示 1.4树的实际应用 2.二叉树 2.1二叉树的概念 2.2特殊的二叉树 2.2.1 满二叉树 2.2.2 完全二叉树 2.2.3堆 2.3 二叉树的性质 2.4二叉树的存储 2.4.1顺序结构存储 2.4.2链式结构存储 2.5二叉树的遍历 2.5.1前序遍历 代码表示 2.5.2中序遍历 代码表示 2.5.3后续遍历 代码表示 2.5.4层序遍历 代码表示 总结示例 2.6二叉树的其他代码 1.树 1.1树的概念 树这个东东,真的不同于之前学到的数据结构 树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。 有一个特殊的结点,称为根结点,根结点没有前驱结点除根结点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1<=i<=m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继树是递归定义的。 如图: 注意:子树与子树之间不能相连,不然就变成另一种数据结构——图 1.2树的相关概念 结点的度:一个结点含有的子树的个数称为该结点的度; 如上图:A的为6 叶结点或终端结点:度为0的结点称为叶结点; 如上图:B、C、H、I...等结点为叶结点 非终端结点或分支结点:度不为0的结点; 如上图:D、E、F、G...等结点为分支结点 双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点; 如上图:A是B的父结点 孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点; 如上图:B是A的孩子结点 兄弟结点:具有相同父结点的结点互称为兄弟结点; 如上图:B、C是兄弟结点 树的度:一棵树中,最大的结点的度称为树的度; 如上图:树的度为6 结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推; 树的高度或深度:树中结点的最大层次; 如上图:树的高度为4 堂兄弟结点:双亲在同一层的结点互为堂兄弟;如上图:H、I互为兄弟结点 结点的祖先:从根到该结点所经分支上的所有结点;如上图:A是所有结点的祖先 子孙:以某结点为根的子树中任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙 森林:由m(m>0)棵互不相交的树的集合称为森林; 1.3树的表示 树结构相对线性表结构比较复杂,要存储表示起来比较麻烦,因为既要保存值,也要保存结点和结点之间的关系 实际中树有很多种表示方式如:双亲表示法,孩子表示法、孩子双亲表示法以及孩子兄弟表示法 等。我们这里就简单的了解其中最常用的孩子兄弟表示法。 所谓孩子兄弟表示法就是左孩子右兄弟(节点的分支左边第一个是孩子,剩下的都是兄弟)如图所示: 1.4树的实际应用 2.二叉树 2.

【java SE语法篇】1. 运算符

目录 1. 运算符和表达式2. 算数运算符3. 隐式转换4. 强制转换5. 自增自减运算符6. 赋值运算符7. 扩展运算符8. 关系运算符9. 逻辑运算符9.1 & 和 | 的使用:9.2 ^(异或)的使用:9.3 !(取反)的使用: 10. 短路逻辑运算符11. 三元运算符 1. 运算符和表达式 运算符: 就是对常量或者变量进行操作的符号。 比如: + - * / 表达式: 用运算符把常量或者变量连接起来的,符合Java语法的式子就是表达式。 比如:a + b 这个整体就是表达式。 ​而其中+是算术运算符的一种,所以这个表达式也称之为算术表达式。 2. 算数运算符 分类: + - * / % 运算特点: + - * :跟小学数学中一模一样没有任何区别. /: 1.整数相除结果只能得到整除,如果结果想要是小数,必须要有小数参数。 2.小数直接参与运算,得到的结果有可能是不精确的。 案例: System.out.println( 10 / 3);//3 System.out.println(10.0 / 3);//3.3333333333333335 %:取模、取余。 他做的也是除法运算,只不过获取的是余数而已。 案例: System.out.println(10 % 2);//0 System.out.println(10 % 3);//1 应用场景: //可以利用取模来判断一个数是奇数还是偶数 System.

【linux】vim

🔥个人主页:Quitecoder 🔥专栏:linux笔记仓 目录 01.vim的基本概念02.基本操作03.正常模式命令集04.批量化注释与去注释05.sudo提权06.vim配置 01.vim的基本概念 Vim是一款高度配置化的文本编辑器,用于创建和编辑任何类型的文本,包括程序代码。它是从“vi”文本编辑器演变而来,增加了一些新功能和改进,包括插件系统、语法高亮、代码折叠、更好的搜索功能等。Vim是一款自由和开源的软件,遵循Vim许可证(它是一种类似于GPL许可证的自由软件许可证)。 vim的三种模式(其实有好多模式,目前掌握这3种即可),分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下: 正常/普通/命令模式(Normal mode) 控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode插入模式(Insert mode) 只有在Insert mode下,才可以做文字输入,按「ESC」键可回到命令行模式。该模式是我们后面用的最频繁的编辑模式。末行模式(last line mode) 文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。 在命令模式下,shift+: 即可进入该模式。要查看你的所有模式:打开vim,底行模式直接输入 :help vim-modes 02.基本操作 vim的基本操作: 进入vim,在系统提示符号输入vim及文件名称后,就进入vim全屏幕编辑画面: $ vim test.c不过有一点要特别注意,就是你进入vim之后,是处于[正常模式],你要切换到[插入模式]才能够输入文字。 [正常模式]切换至[插入模式] 输入a输入i输入o [插入模式]切换至[正常模式] 目前处于[插入模式],就只能一直输入文字,如果发现输错了字,想用光标键往回移动,将该字删除,可以先按一下**「ESC」键**转到[正常模式]再删除文字。当然,也可以直接删除。 [正常模式]切换至[末行模式] 「shift + ;」, 其实就是输入「:」 退出vim及保存文件,在[正常模式]下,按一下「:」冒号键进入「Last line mode」,例如: : w (保存当前文件): wq (输入「wq」,存盘并退出vim): q! (输入q!,不存盘强制退出vim) 03.正常模式命令集 插入模式 按「i」切换进入插入模式「insert mode」,按“i”进入插入模式后是从光标当前位置开始输入文件;按「a」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字;按「o」进入插入模式后,是插入新的一行,从行首开始输入文字。 从插入模式切换为命令模式 按「ESC」键。 移动光标 vim可以直接用键盘上的光标来上下左右移动,但正规的vim是用小写英文字母 「h」、「j」、「k」、「l」,分别控制光标左、下、上、右移一格按「G」:移动到文章的最后按「 $ 」:移动到光标所在行的“行尾”按「^」:移动到光标所在行的“行首”按「w」:光标跳到下个字的开头按「e」:光标跳到下个字的字尾按「b」:光标回到上个字的开头按「#l」:光标移到该行的第#个位置,如:5l,56l按[gg]:进入到文本开始按[shift+g]:进入文本末端按[#shift+g]:进入第#行按「ctrl」+「b」:屏幕往“后”移动一页按「ctrl」+「f」:屏幕往“前”移动一页按「ctrl」+「u」:屏幕往“后”移动半页按「ctrl」+「d」:屏幕往“前”移动半页 删除文字 「x」:每按一次,删除光标所在位置的一个字符「#x」:例如,「6x」表示删除光标所在位置的“后面(包含自己在内)”6个字符「X」:大写的X,每按一次,删除光标所在位置的“前面”一个字符「#X」:例如,「20X」表示删除光标所在位置的“前面”20个字符「dd」:删除光标所在行「#dd」:从光标所在行开始删除#行 复制 「yw」:将光标所在之处到字尾的字符复制到缓冲区中。「#yw」:复制#个字到缓冲区「yy」:复制光标所在行到缓冲区。「#yy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字。「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能。 替换 「r」:替换光标所在处的字符。「R」:替换光标所到之处的字符,直到按下「ESC」键为止。 撤销上一次操作 「u」:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可以执行多次回复。「ctrl + r」: 撤销的恢复 更改 「cw」:更改光标所在处的字到字尾处「c#w」:例如,「c3w」表示更改3个字 跳至指定的行 「ctrl」+「g」列出光标所在行的行号。「#G」:例如,「15G」,表示移动光标至文章的第15行行首

6 Go语言的常量、枚举、作用域

本专栏将从基础开始,循序渐进,由浅入深讲解Go语言,希望大家都能够从中有所收获,也请大家多多支持。 查看相关资料与知识库 专栏地址:Go专栏 如果文章知识点有错误的地方,请指正!大家一起学习,一起进步。 文章目录 常量练习 1.16 – 常量预期输出 枚举作用域 常量 常量类似于变量,但其初始值不能更改。在需要代码运行时保持不变的值的情况下,使用常量非常有用。虽然可以将这些值硬编码到代码中以实现类似效果,但经验表明,虽然这些值在运行时不需要更改,但将来可能需要更改。如果发生这种情况,追踪和修复所有硬编码的值可能是一项繁琐且容易出错的任务。使用常量可以节省大量的后续维护工作。 常量声明类似于 var 语句。定义常量时,必须指定初始值。类型是可选的,如果省略,类型将会被推断。初始值可以是文字值或简单的表达式,并且可以使用其他常量的值。与 var 一样,可以在一个语句中声明多个常量。以下是常量声明的语法: const <name> <type> = <value> const ( <name1> <type1> = <value1> <name2> <type2> = <value2> … <nameN> <typeN> = <valueN> ) 练习 1.16 – 常量 在这个练习中,我们遇到了一个性能问题:我们的数据库服务器太慢了。我们将创建一个自定义内存缓存。我们会使用 Go 的 map 集合类型作为缓存。缓存中可以存储的项目数量有一个全局限制。我们将使用一个 map 来帮助跟踪缓存中的项目数量。我们需要缓存两种类型的数据:书籍和 CD。两者都使用 ID,因此我们需要一种方法来区分共享缓存中的两种类型的项目。我们需要一种方法来设置和获取缓存中的项目。 我们将设置缓存中的最大项目数量。我们还将使用常量添加前缀,以区分书籍和 CD。让我们开始吧: 创建一个新的文件夹,并在其中添加一个 main.go 文件。 在 main.go 文件的顶部添加 main 包名: package main 导入我们需要的包: import "fmt" 创建一个表示全局限制大小的常量: const GlobalLimit = 100 创建一个 MaxCacheSize 常量,它是全局限制大小的 10 倍: