C++ 入门进阶之十一
大纲
- C++ 入门进阶之一、C++ 入门进阶之二、C++ 入门进阶之三
- C++ 入门进阶之四、C++ 入门进阶之五、C++ 入门进阶之六
- C++ 入门进阶之七、C++ 入门进阶之八、C++ 入门进阶之九
- C++ 入门进阶之十、C++ 入门进阶之十一
算法
算法的基本概念
算法的简介
函数库对数据类型的选择对其可重用性起着至关重要的作用。举例来说,一个求方根的函数,在使用浮点数作为其参数类型的情况下的可重用性肯定比使用整型作为它的参数类性要高。而 C++ 通过模板的机制允许推迟对某些类型的选择,直到真正想使用模板或者说对模板进行特化的时候,STL 就利用了这一点提供了相当多的算法。它是在一个有效的框架中完成这些算法的 —— 可以将所有的类型划分为少数的几类,然后就可以在模板的参数中使用一种类型替换掉同一种类中的其他类型。
Kafka 2.x 入门教程之二
大纲
- Kafka 2.x 入门教程之一、Kafka 2.x 入门教程之二、Kafka 2.x 入门教程之三
- Kafka 2.x 入门教程之四、Kafka 2.x 入门教程之五、Kafka 2.x 入门教程之六
- Kafka 2.x 入门教程之七、Kafka 2.x 入门教程之八
前言
学习资源
Kafka 生产者
生产者消息发送流程
生产者消息发送原理
Kafka 的 Producer 发送消息采用的是异步发送的方式。在消息发送的过程中,涉及到了两个线程 — main 线程和 sender 线程。在 main 线程中,会创建一个双端队列 RecordAccumulator。值得一提的是,main 线程将消息发送给 RecordAccumulator 时,sender 线程会不断从 RecordAccumulator 中拉取消息并发送到 Kafka Broker。

C++ 入门进阶之十
大纲
- C++ 入门进阶之一、C++ 入门进阶之二、C++ 入门进阶之三
- C++ 入门进阶之四、C++ 入门进阶之五、C++ 入门进阶之六
- C++ 入门进阶之七、C++ 入门进阶之八、C++ 入门进阶之九
- C++ 入门进阶之十、C++ 入门进阶之十一
函数对象
函数对象的概念
尽管函数指针被广泛用于实现函数回调,但 C++ 还提供了一个重要的实现回调函数的方法,那就是函数对象。重载函数调用操作符 () 的类,其对象常称为函数对象(Function Object),即它们是行为类似函数的对象。一个类对象,表现出一个函数的特征,就是通过 对象名 + (参数列表) 的方式使用一个类对象,如果没有上下文,完全可以把它看作一个函数对待,这是通过重载类的 () 操作符来实现的。在 C++ 标准库中,函数对象被广泛地使用以获得弹性,并且标准库中的很多算法都可以使用函数对象或者函数来作为自定义的回调行为。值得一提的是,函数对象的别名是 仿函数,或者是 伪函数。
Kafka 2.x 入门教程之一
大纲
- Kafka 2.x 入门教程之一、Kafka 2.x 入门教程之二、Kafka 2.x 入门教程之三
- Kafka 2.x 入门教程之四、Kafka 2.x 入门教程之五、Kafka 2.x 入门教程之六
- Kafka 2.x 入门教程之七、Kafka 2.x 入门教程之八
前言
学习资源
消息队列
目前企业中比较常见的消息队列产品主要有 Kafka、RabbitMQ、RocketMQ、ActiveMQ 等。在大数据场景主要采用 Kafka 作为消息队列,而在 JavaEE 开发中主要采用 RabbitMQ、RocketMQ、ActiveMQ。
消息队列的优势
解耦- 允许独立地扩展或修改不同业务的处理过程,只要确保它们遵守同样的接口约束

Linux 生产环境搭建 Kafka 集群
大纲
Kafka 单机部署
Kafka 集群部署
前言
本文将使用多台物理机器(至少三台)搭建 Kafka 集群,适用于 CentOS/Debian/Ubuntu 等发行版。
Zookeeper 集群搭建
本文的 Kafka 集群搭建依赖于 Zookeeper,因此生产环境需要将 Zookeeper 集群提前搭建起来。值得一提的是,从 Kafka 2.8.0 版本开始,Kafka 自身实现了 Raft 分布式一致性机制,这意味着 Kafka 集群是可以脱离 ZooKeeper 独立运行的。
集群规划
| 节点 | IP 地址 | 端口 | 版本号 |
|---|---|---|---|
| Zookeeper 节点 1 | 192.168.1.1 | 2181 | 3.4.10 |
| Zookeeper 节点 2 | 192.168.1.2 | 2181 | 3.4.10 |
| Zookeeper 节点 3 | 192.168.1.3 | 2181 | 3.4.10 |
Linux 单机搭建 Kafka 集群
大纲
Kafka 单机部署
Kafka 集群部署
前言
本文适用于在 Centos/Debian/Ubuntu 等 Linux 发行版系统上,使用单机搭建 Kafka 集群。
Zookeeper 集群搭建
本文的 Kafka 集群搭建依赖于 Zookeeper,因此需要将 Zookeeper 单机集群提前搭建起来。值得一提的是,从 Kafka 2.8.0 版本开始,Kafka 自身实现了 Raft 分布式一致性机制,这意味着 Kafka 集群是可以脱离 ZooKeeper 独立运行的。
集群规划
| 节点 | IP 地址 | 端口 | 版本号 |
|---|---|---|---|
| Zookeeper 节点 1 | 127.0.0.1 | 2181 | 3.4.10 |
| Zookeeper 节点 2 | 127.0.0.1 | 2182 | 3.4.10 |
| Zookeeper 节点 3 | 127.0.0.1 | 2183 | 3.4.10 |
C++ 入门进阶之九
大纲
- C++ 入门进阶之一、C++ 入门进阶之二、C++ 入门进阶之三
- C++ 入门进阶之四、C++ 入门进阶之五、C++ 入门进阶之六
- C++ 入门进阶之七、C++ 入门进阶之八、C++ 入门进阶之九
- C++ 入门进阶之十、C++ 入门进阶之十一
set 与 multiset 容器
set 与 multiset 容器的概念
set 容器的概念
set 是一个集合容器,其中所包含的元素是唯一的,集合中的元素会自动按一定的顺序排列。元素插入过程是按排序规则插入,所以不能指定插入位置。set 的元素不像 map 那样可以同时拥有实值和键值,set 的元素即是键值又是实值。Set 不允许两个元素有相同的键,也不可以通过 set 的迭代器改变 set 元素的值,因为 set 元素值就是其键值,关系到 set 元素的排序规则。如果任意改变 set 元素值,会严重破坏 set 的组织。换句话说 set 的 iterator 是一种 const iterator。set 拥有和 list 某些相同的性质,当对容器中的元素进行插入操作或者删除操作的时候,操作之前所有的迭代器,在操作完成之后依然有效,被删除的那个元素的迭代器必然是一个例外。
C++ 入门进阶之八
大纲
- C++ 入门进阶之一、C++ 入门进阶之二、C++ 入门进阶之三
- C++ 入门进阶之四、C++ 入门进阶之五、C++ 入门进阶之六
- C++ 入门进阶之七、C++ 入门进阶之八、C++ 入门进阶之九
- C++ 入门进阶之十、C++ 入门进阶之十一
list 容器
list 容器的概念
list 是一个双向链表容器,而且还是一个双向循环链表,可以高效地进行插入和删除元素。链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的(如下图所示)。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。相较于 vector 的连续线性空间,list 就显得负责许多,它的好处是每次插入或者删除一个元素,就是配置或者释放一个元素的空间。因此,list 对于空间的运用有绝对的精准,一点也不浪费。值得一提的是,对于任何位置的元素插入或元素的移除,list 永远是常数时间的耗时(效率较高);但对于查询操作来说,list 的执行效率较低。

总结
- 链表采用动态内存分配,不会造成内存浪费和溢出。
- 链表虽然灵活,但是空间和时间的额外耗费较大。
- 链表执行插入和删除操作都十分方便,仅修改指针即可实现,不需要移动大量元素。
- 链表不可以随机存取元素,所以不支持
at.(pos)函数与[]操作符的使用。
list 容器的迭代器
list 容器不能像 vector 一样以普通指针作为迭代器,因为其节点不能保证都在同一块连续的内存空间上。list 迭代器必须有能力指向 list 的节点,并有能力进行正确的递增、递减、取值、成员存取操作。所谓 “list 正确的递增、递减、取值、成员取用” 是指,递增时指向下一个节点,递减时指向上一个节点,取值时取的是节点的数据值,成员取用时取的是节点的成员。由于 list 是一个双向链表,迭代器必须能够具备前移、后移的能力,所以 list 容器提供的迭代器是 BidirectionalIterators。list 有一个重要的性质,插入操作和删除操作都不会造成原有 list 送代器的失效。这在 vector 是不成立的,因为 vector 的插入操作可能造成记忆体重新配置,导致原有的送代器全部失效;甚至 list 元素的删除,也只有被删除的那个元素的迭代器失效,其他迭代器不受任何影响。
list 容器的使用
list 的构造与赋值
默认构造函数
list 采用模板类实现,对象的默认构造形式:list<T> lstT;,其中 <> 尖括号内还可以设置指针类型或自定义类型
1 | list<int> lstInt; // 定义一个存放 int 数据的 list 容器 |
有参构造函数
1 | list(beg, end); // 构造函数将 [beg, end) 区间中的元素拷贝给本身,注意该区间是左闭右开的区间 |
赋值操作说明
1 | list.assign(beg, end); // 构造函数将 [beg, end) 区间中的元素拷贝给本身,注意该区间是左闭右开的区间 |
构造与赋值的使用
1 | #include <iostream> |
程序运行输出的结果如下:
1 | ------ list 构造函数 ------ |
list 的常用操作
1 | #include <iostream> |
程序运行输出的结果如下:
1 | ------ list 插入操作 ------ |
list 的反转与排序操作
提示
- 所有不支持随机访问的容器,都不可以使用系统提供的排序算法。
- 如果容器不支持使用系统提供的排序算法,那么这个容器的内部往往会提供对应的排序算法。
1 | #include <iostream> |
程序运行输出的结果如下:
1 | ------ list 反转操作 ------ |
list 的自定义数据类型操作
提示
- 对 list 的自定义类型数据类型进行排序时,必须指定排序规则。
- 调用
remove()函数移除 list 容器中的元素时,自定义数据类型必须重载==双等号操作符,否则移除操作会执行失败。
1 | #include <iostream> |
程序运行输出的结果如下:
1 | ------ list 插入操作(自定义数据类型) ------ |
stack 容器
stack 容器的概念
stack 是堆栈容器,属于一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口。stack 容器允许新增元素、移除元素、取得栈顶元素,但是除了最顶端的元素外,没有任何其他方法可以存取 stack 中的其他元素。stack 没有迭代器,容器中所有元素的进出都必须符合 “先进后出” 的规则,只有 stack 最顶端的元素,才有机会被外界取用。换言之,stack 不提供遍历功能,也不提供迭代器。deque 是双向开口的数据结构,若以 deque 为底部结构并封闭其头端开口,便轻而易举地形成一个 stack。因此,SGI STL 便以 deque 作为缺省情况下的 stack 底部结构。由于 stack 以 deque 做为底部容器完成其所有工作,而具有这种 “修改某物接口,形成另一种风貌” 的性质者,称为 adapter(配接器),因此,stack 往往不被归类为 container(容器),而被归类为 container adapter(容器配接器)。简而言之,stack 是简单地装饰 deque 容器而成为另外的一种容器。

