Compare commits
11 Commits
bee17dc6cd
...
f0a75ccbd4
Author | SHA1 | Date | |
---|---|---|---|
|
f0a75ccbd4 | ||
|
65c11b151f | ||
|
7af119baad | ||
|
70eac8accb | ||
|
32e88b7f45 | ||
|
a09632f9be | ||
|
abaa691ffa | ||
|
897c4d26a3 | ||
|
8782ebb5e5 | ||
|
4e0a0147fe | ||
|
59e5728e6a |
@ -7,6 +7,7 @@ export const highQualityTechnicalArticles = arraySidebar([
|
||||
prefix: "advanced-programmer/",
|
||||
collapsible: false,
|
||||
children: [
|
||||
"programmer-quickly-learn-new-technology",
|
||||
"the-growth-strategy-of-the-technological-giant",
|
||||
"ten-years-of-dachang-growth-road",
|
||||
"seven-tips-for-becoming-an-advanced-programmer",
|
||||
|
@ -239,6 +239,8 @@ export default sidebar({
|
||||
icon: "suanfaku",
|
||||
collapsible: true,
|
||||
children: [
|
||||
"classical-algorithm-problems-recommendations",
|
||||
"common-data-structures-leetcode-recommendations",
|
||||
"string-algorithm-problems",
|
||||
"linkedlist-algorithm-problems",
|
||||
"the-sword-refers-to-offer",
|
||||
|
@ -0,0 +1,114 @@
|
||||
---
|
||||
title: 经典算法思想总结(含LeetCode题目推荐)
|
||||
category: 计算机基础
|
||||
tag:
|
||||
- 算法
|
||||
---
|
||||
|
||||
## 贪心算法
|
||||
|
||||
### 算法思想
|
||||
|
||||
贪心的本质是选择每一阶段的局部最优,从而达到全局最优。
|
||||
|
||||
### 一般解题步骤
|
||||
|
||||
- 将问题分解为若干个子问题
|
||||
- 找出适合的贪心策略
|
||||
- 求解每一个子问题的最优解
|
||||
- 将局部最优解堆叠成全局最优解
|
||||
|
||||
### LeetCode
|
||||
|
||||
455.分发饼干:https://leetcode.cn/problems/assign-cookies/
|
||||
|
||||
121.买卖股票的最佳时机:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/
|
||||
|
||||
122.买卖股票的最佳时机 II:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/
|
||||
|
||||
55.跳跃游戏:https://leetcode.cn/problems/jump-game/
|
||||
|
||||
45.跳跃游戏 II:https://leetcode.cn/problems/jump-game-ii/
|
||||
|
||||
## 动态规划
|
||||
|
||||
### 算法思想
|
||||
|
||||
动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的。
|
||||
|
||||
经典题目:01 背包、完全背包
|
||||
|
||||
### 一般解题步骤
|
||||
|
||||
- 确定 dp 数组(dp table)以及下标的含义
|
||||
- 确定递推公式
|
||||
- dp 数组如何初始化
|
||||
- 确定遍历顺序
|
||||
- 举例推导 dp 数组
|
||||
|
||||
### LeetCode
|
||||
|
||||
509.斐波那契数:https://leetcode.cn/problems/fibonacci-number/
|
||||
|
||||
746.使用最小花费爬楼梯:https://leetcode.cn/problems/min-cost-climbing-stairs/
|
||||
|
||||
416.分割等和子集:https://leetcode.cn/problems/partition-equal-subset-sum/
|
||||
|
||||
518.零钱兑换:https://leetcode.cn/problems/coin-change-ii/
|
||||
|
||||
647.回文子串:https://leetcode.cn/problems/palindromic-substrings/
|
||||
|
||||
516.最长回文子序列:https://leetcode.cn/problems/longest-palindromic-subsequence/
|
||||
|
||||
## 回溯算法
|
||||
|
||||
### 算法思想
|
||||
|
||||
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条
|
||||
|
||||
件时,就“回溯”返回,尝试别的路径。其本质就是穷举。
|
||||
|
||||
经典题目:8 皇后
|
||||
|
||||
### 一般解题步骤
|
||||
|
||||
- 针对所给问题,定义问题的解空间,它至少包含问题的一个(最优)解。
|
||||
- 确定易于搜索的解空间结构,使得能用回溯法方便地搜索整个解空间 。
|
||||
- 以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。
|
||||
|
||||
### leetcode
|
||||
|
||||
77.组合:https://leetcode.cn/problems/combinations/
|
||||
|
||||
39.组合总和:https://leetcode.cn/problems/combination-sum/
|
||||
|
||||
40.组合总和 II:https://leetcode.cn/problems/combination-sum-ii/
|
||||
|
||||
78.子集:https://leetcode.cn/problems/subsets/
|
||||
|
||||
90.子集 II:https://leetcode.cn/problems/subsets-ii/
|
||||
|
||||
51.N 皇后:https://leetcode.cn/problems/n-queens/
|
||||
|
||||
## 分治算法
|
||||
|
||||
### 算法思想
|
||||
|
||||
将一个规模为 N 的问题分解为 K 个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。
|
||||
|
||||
经典题目:二分查找、汉诺塔问题
|
||||
|
||||
### 一般解题步骤
|
||||
|
||||
- 将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
|
||||
- 若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题
|
||||
- 将各个子问题的解合并为原问题的解。
|
||||
|
||||
### LeetCode
|
||||
|
||||
108.将有序数组转换成二叉搜索数:https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/
|
||||
|
||||
148.排序列表:https://leetcode.cn/problems/sort-list/
|
||||
|
||||
23.合并 k 个升序链表:https://leetcode.cn/problems/merge-k-sorted-lists/
|
||||
|
@ -0,0 +1,67 @@
|
||||
---
|
||||
title: 常见数据结构经典LeetCode题目推荐
|
||||
category: 计算机基础
|
||||
tag:
|
||||
- 算法
|
||||
---
|
||||
|
||||
## 数组
|
||||
|
||||
704.二分查找:https://leetcode.cn/problems/binary-search/
|
||||
|
||||
80.删除有序数组中的重复项 II:https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii
|
||||
|
||||
977.有序数组的平方:https://leetcode.cn/problems/squares-of-a-sorted-array/
|
||||
|
||||
## 链表
|
||||
|
||||
707.设计链表:https://leetcode.cn/problems/design-linked-list/
|
||||
|
||||
206.反转链表:https://leetcode.cn/problems/reverse-linked-list/
|
||||
|
||||
92.反转链表 II:https://leetcode.cn/problems/reverse-linked-list-ii/
|
||||
|
||||
61.旋转链表:https://leetcode.cn/problems/rotate-list/
|
||||
|
||||
## 栈与队列
|
||||
|
||||
232.用栈实现队列:https://leetcode.cn/problems/implement-queue-using-stacks/
|
||||
|
||||
225.用队列实现栈:https://leetcode.cn/problems/implement-stack-using-queues/
|
||||
|
||||
347.前 K 个高频元素:https://leetcode.cn/problems/top-k-frequent-elements/
|
||||
|
||||
239.滑动窗口最大值:https://leetcode.cn/problems/sliding-window-maximum/
|
||||
|
||||
## 二叉树
|
||||
|
||||
105.从前序与中序遍历构造二叉树:https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
|
||||
|
||||
117.填充每个节点的下一个右侧节点指针 II:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii
|
||||
|
||||
236.二叉树的最近公共祖先:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/
|
||||
|
||||
129.求根节点到叶节点数字之和:https://leetcode.cn/problems/sum-root-to-leaf-numbers/
|
||||
|
||||
102.二叉树的层序遍历:https://leetcode.cn/problems/binary-tree-level-order-traversal/
|
||||
|
||||
530.二叉搜索树的最小绝对差:https://leetcode.cn/problems/minimum-absolute-difference-in-bst/
|
||||
|
||||
## 图
|
||||
|
||||
200.岛屿数量:https://leetcode.cn/problems/number-of-islands/
|
||||
|
||||
207.课程表:https://leetcode.cn/problems/course-schedule/
|
||||
|
||||
210.课程表 II:https://leetcode.cn/problems/course-schedule-ii/
|
||||
|
||||
## 堆
|
||||
|
||||
215. 数组中的第 K 个最大元素:https://leetcode.cn/problems/kth-largest-element-in-an-array/
|
||||
|
||||
215. 数据流的中位数:https://leetcode.cn/problems/find-median-from-data-stream/
|
||||
|
||||
215. 前 K 个高频元素:https://leetcode.cn/problems/top-k-frequent-elements/
|
||||
|
||||
|
||||
|
BIN
docs/cs-basics/data-structure/pictures/红黑树/红黑树1.PNG
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/cs-basics/data-structure/pictures/红黑树/红黑树1.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/cs-basics/data-structure/pictures/红黑树/红黑树2.PNG
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/cs-basics/data-structure/pictures/红黑树/红黑树2.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/cs-basics/data-structure/pictures/红黑树/红黑树3.PNG
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
docs/cs-basics/data-structure/pictures/红黑树/红黑树3.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
docs/cs-basics/data-structure/pictures/红黑树/红黑树4.PNG
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/cs-basics/data-structure/pictures/红黑树/红黑树4.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/cs-basics/data-structure/pictures/红黑树/红黑树5.PNG
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
docs/cs-basics/data-structure/pictures/红黑树/红黑树5.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
docs/cs-basics/data-structure/pictures/红黑树/红黑树6.PNG
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/cs-basics/data-structure/pictures/红黑树/红黑树6.png
Normal file
After Width: | Height: | Size: 11 KiB |
@ -1,23 +1,94 @@
|
||||
---
|
||||
title: 红黑树
|
||||
category: 计算机基础
|
||||
tag:
|
||||
- 数据结构
|
||||
---
|
||||
|
||||
# 红黑树
|
||||
## 红黑树介绍
|
||||
|
||||
**红黑树特点** :
|
||||
红黑树(Red Black Tree)是一种自平衡二叉查找树。它是在 1972 年由 Rudolf Bayer 发明的,当时被称为平衡二叉 B 树(symmetric binary B-trees)。后来,在 1978 年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”。
|
||||
|
||||
1. 每个节点非红即黑;
|
||||
2. 根节点总是黑色的;
|
||||
3. 每个叶子节点都是黑色的空节点(NIL 节点);
|
||||
4. 如果节点是红色的,则它的子节点必须是黑色的(反之不一定);
|
||||
5. 从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)。
|
||||
由于其自平衡的特性,保证了最坏情形下在 O(logn) 时间复杂度内完成查找、增加、删除等操作,性能表现稳定。
|
||||
|
||||
**红黑树的应用**:TreeMap、TreeSet 以及 JDK1.8 的 HashMap 底层都用到了红黑树。
|
||||
在 JDK 中,`TreeMap`、`TreeSet` 以及 JDK1.8 的 `HashMap` 底层都用到了红黑树。
|
||||
|
||||
**为什么要用红黑树?** 简单来说红黑树就是为了解决二叉查找树的缺陷,因为二叉查找树在某些情况下会退化成一个线性结构。详细了解可以查看 [漫画:什么是红黑树?](https://juejin.im/post/5a27c6946fb9a04509096248#comment)(也介绍到了二叉查找树,非常推荐)
|
||||
## 为什么需要红黑树?
|
||||
|
||||
**相关阅读**:[《红黑树深入剖析及 Java 实现》](https://zhuanlan.zhihu.com/p/24367771)(美团点评技术团队)
|
||||
红黑树的诞生就是为了解决二叉查找树的缺陷。
|
||||
|
||||
二叉查找树是一种基于比较的数据结构,它的每个节点都有一个键值,而且左子节点的键值小于父节点的键值,右子节点的键值大于父节点的键值。这样的结构可以方便地进行查找、插入和删除操作,因为只需要比较节点的键值就可以确定目标节点的位置。但是,二叉查找树有一个很大的问题,就是它的形状取决于节点插入的顺序。如果节点是按照升序或降序的方式插入的,那么二叉查找树就会退化成一个线性结构,也就是一个链表。这样的情况下,二叉查找树的性能就会大大降低,时间复杂度就会从 O(logn) 变为 O(n)。
|
||||
|
||||
红黑树的诞生就是为了解决二叉查找树的缺陷,因为二叉查找树在某些情况下会退化成一个线性结构。
|
||||
|
||||
## **红黑树特点**
|
||||
|
||||
1. 每个节点非红即黑。黑色决定平衡,红色不决定平衡。这对应了 2-3 树中一个节点内可以存放 1~2 个节点。
|
||||
2. 根节点总是黑色的。
|
||||
3. 每个叶子节点都是黑色的空节点(NIL 节点)。这里指的是红黑树都会有一个空的叶子节点,是红黑树自己的规则。
|
||||
4. 如果节点是红色的,则它的子节点必须是黑色的(反之不一定)。通常这条规则也叫不会有连续的红色节点。一个节点最多临时会有 3 个节点,中间是黑色节点,左右是红色节点。
|
||||
5. 从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)。每一层都只是有一个节点贡献了树高决定平衡性,也就是对应红黑树中的黑色节点。
|
||||
|
||||
正是这些特点才保证了红黑树的平衡,让红黑树的高度不会超过 2log(n+1)。
|
||||
|
||||
|
||||
## 红黑树数据结构
|
||||
|
||||
建立在 BST 二叉搜索树的基础上,AVL、2-3 树、红黑树都是自平衡二叉树(统称 B-树)。但相比于 AVL 树,高度平衡所带来的时间复杂度,红黑树对平衡的控制要宽松一些,红黑树只需要保证黑色节点平衡即可。
|
||||
|
||||
## 红黑树结构实现
|
||||
|
||||
```java
|
||||
public class Node {
|
||||
|
||||
public Class<?> clazz;
|
||||
public Integer value;
|
||||
public Node parent;
|
||||
public Node left;
|
||||
public Node right;
|
||||
|
||||
// AVL 树所需属性
|
||||
public int height;
|
||||
// 红黑树所需属性
|
||||
public Color color = Color.RED;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### 1.左倾染色
|
||||
|
||||

|
||||
|
||||
- 染色时根据当前节点的爷爷节点,找到当前节点的叔叔节点。
|
||||
- 再把父节点染黑、叔叔节点染黑,爷爷节点染红。但爷爷节点染红是临时的,当平衡树高操作后会把根节点染黑。
|
||||
|
||||
### 2.右倾染色
|
||||
|
||||

|
||||
|
||||
### 3.左旋调衡
|
||||
|
||||
#### 3.1 一次左旋
|
||||
|
||||

|
||||
|
||||
#### 3.2 右旋+左旋
|
||||
|
||||

|
||||
|
||||
### 4.右旋调衡
|
||||
|
||||
#### 4.1 一次右旋
|
||||
|
||||

|
||||
|
||||
#### 4.2 左旋+右旋
|
||||
|
||||

|
||||
|
||||
## 文章推荐
|
||||
|
||||
- [《红黑树深入剖析及 Java 实现》 - 美团点评技术团队](https://zhuanlan.zhihu.com/p/24367771)
|
||||
- [漫画:什么是红黑树? - 程序员小灰](https://juejin.im/post/5a27c6946fb9a04509096248#comment)(也介绍到了二叉查找树,非常推荐)
|
||||
|
||||
<!-- @include: @article-footer.snippet.md -->
|
||||
|
@ -90,7 +90,7 @@ MySQL 字段类型比较多,我这里会挑选一些日常开发使用很频
|
||||
|
||||
MySQL 中的整数类型可以使用可选的 UNSIGNED 属性来表示不允许负值的无符号整数。使用 UNSIGNED 属性可以将正整数的上限提高一倍,因为它不需要存储负数值。
|
||||
|
||||
例如, TINYINT UNSIGNED 类型的取值范围是 0 ~ 255,而普通的 TINYINT 类型的值范围是 -128 ~ 127。INT UNSIGNED 类型的取值范围是 0 ~ 4,294,967,295,而普通的 INT 类型的值范围是 2,147,483,648 ~ 2,147,483,647。
|
||||
例如, TINYINT UNSIGNED 类型的取值范围是 0 ~ 255,而普通的 TINYINT 类型的值范围是 -128 ~ 127。INT UNSIGNED 类型的取值范围是 0 ~ 4,294,967,295,而普通的 INT 类型的值范围是 -2,147,483,648 ~ 2,147,483,647。
|
||||
|
||||
对于从 0 开始递增的 ID 列,使用 UNSIGNED 属性可以非常适合,因为不允许负值并且可以拥有更大的上限范围,提供了更多的 ID 值可用。
|
||||
|
||||
|
@ -282,7 +282,14 @@ Snowflake 是 Twitter 开源的分布式 ID 生成算法。Snowflake 由 64 bit
|
||||
我们再来看看 Snowflake 算法的优缺点:
|
||||
|
||||
- **优点**:生成速度比较快、生成的 ID 有序递增、比较灵活(可以对 Snowflake 算法进行简单的改造比如加入业务 ID)
|
||||
- **缺点**:需要解决重复 ID 问题(依赖时间,当机器时间不对的情况下,可能导致会产生重复 ID)。
|
||||
- **缺点**:需要解决重复 ID 问题(ID 生成依赖时间,在获取时间的时候,可能会出现时间回拨的问题,也就是服务器上的时间突然倒退到之前的时间,进而导致会产生重复 ID)、依赖机器 ID 对分布式环境不友好(当需要自动启停或增减机器时,固定的机器 ID 可能不够灵活)。
|
||||
|
||||
针对雪花算法的时间回拨问题和依赖机器 ID 的问题,一些基于雪花算法的开源框架都有自己的解决方案,比如百度的 UIDGenerator 和 美团的 Leaf (后面会提到)。
|
||||
|
||||
并且,Seata 还提出了“改良版雪花算法”,针对原版雪花算法进行了一定的优化改良,解决了时间回拨问题,大幅提高的 QPS。具体介绍和改进原理,可以参考下面这两篇文章:
|
||||
|
||||
- [Seata 基于改良版雪花算法的分布式 UUID 生成器分析](https://seata.io/zh-cn/blog/seata-analysis-UUID-generator.html)
|
||||
- [在开源项目中看到一个改良版的雪花算法,现在它是你的了。](https://www.cnblogs.com/thisiswhy/p/17611163.html)
|
||||
|
||||
### 开源框架
|
||||
|
||||
@ -294,6 +301,11 @@ Snowflake 是 Twitter 开源的分布式 ID 生成算法。Snowflake 由 64 bit
|
||||
|
||||

|
||||
|
||||
- **sign(1bit)**:符号位(标识正负),始终为 0,没有用,不用管。
|
||||
- **delta seconds (28 bits)**:当前时间,相对于时间基点"2016-05-20"的增量值,单位:秒,最多可支持约 8.7 年
|
||||
- **worker id (22 bits)**: 机器 id,最多可支持约 420w 次机器启动。内置实现为在启动时由数据库分配,默认分配策略为用后即弃,后续可提供复用策略。
|
||||
- **sequence (13 bits)**: 每秒下的并发序列,13 bits 可支持每秒 8192 个并发。
|
||||
|
||||
可以看出,和原始 Snowflake(雪花算法)生成的唯一 ID 的组成不太一样。并且,上面这些参数我们都可以自定义。
|
||||
|
||||
UidGenerator 官方文档中的介绍如下:
|
||||
@ -306,7 +318,7 @@ UidGenerator 官方文档中的介绍如下:
|
||||
|
||||
**[Leaf](https://github.com/Meituan-Dianping/Leaf)** 是美团开源的一个分布式 ID 解决方案 。这个项目的名字 Leaf(树叶) 起源于德国哲学家、数学家莱布尼茨的一句话:“There are no two identical leaves in the world”(世界上没有两片相同的树叶) 。这名字起得真心挺不错的,有点文艺青年那味了!
|
||||
|
||||
Leaf 提供了 **号段模式** 和 **Snowflake(雪花算法)** 这两种模式来生成分布式 ID。并且,它支持双号段,还解决了雪花 ID 系统时钟回拨问题。不过,时钟问题的解决需要弱依赖于 Zookeeper 。
|
||||
Leaf 提供了 **号段模式** 和 **Snowflake(雪花算法)** 这两种模式来生成分布式 ID。并且,它支持双号段,还解决了雪花 ID 系统时钟回拨问题。不过,时钟问题的解决需要弱依赖于 Zookeeper(使用 Zookeeper 作为注册中心,通过在特定路径下读取和创建子节点来管理 workId) 。
|
||||
|
||||
Leaf 的诞生主要是为了解决美团各个业务线生成分布式 ID 的方法多种多样以及不可靠的问题。
|
||||
|
||||
|
@ -38,7 +38,9 @@ head:
|
||||
|
||||
我们可以在应用和数据中间加了一个代理层。应用程序所有的数据请求都交给代理层处理,代理层负责分离读写请求,将它们路由到对应的数据库中。
|
||||
|
||||
提供类似功能的中间件有 **MySQL Router**(官方)、**Atlas**(基于 MySQL Proxy)、**MaxScale**、**MyCat**。
|
||||
提供类似功能的中间件有 **MySQL Router**(官方, MySQL Proxy 的替代方案)、**Atlas**(基于 MySQL Proxy)、**MaxScale**、**MyCat**。
|
||||
|
||||
关于 MySQL Router 多提一点:在 MySQL 8.2 的版本中,MySQL Router 能自动分辨对数据库读写/操作并把这些操作路由到正确的实例上。这是一项有价值的功能,可以优化数据库性能和可扩展性,而无需在应用程序中进行任何更改。具体介绍可以参考官方博客:[MySQL 8.2 – transparent read/write splitting](https://blogs.oracle.com/mysql/post/mysql-82-transparent-readwrite-splitting)。
|
||||
|
||||
**2. 组件方式**
|
||||
|
||||
|
@ -0,0 +1,51 @@
|
||||
---
|
||||
title: 程序员如何快速学习新技术
|
||||
category: 技术文章精选集
|
||||
tag:
|
||||
- 练级攻略
|
||||
---
|
||||
|
||||
> **推荐语**:这是[《Java面试指北》](https://javaguide.cn/zhuanlan/java-mian-shi-zhi-bei.html)练级攻略篇中的一篇文章,分享了我对于如何快速学习一门新技术的看法。
|
||||
>
|
||||
> 
|
||||
|
||||
很多时候,我们因为工作原因需要快速学习某项技术,进而在项目中应用。或者说,我们想要去面试的公司要求的某项技术我们之前没有接触过,为了应对面试需要,我们需要快速掌握这项技术。
|
||||
|
||||
作为一个人纯自学出生的程序员,这篇文章简单聊聊自己对于如何快速学习某项技术的看法。
|
||||
|
||||
学习任何一门技术的时候,一定要先搞清楚这个技术是为了解决什么问题的。深入学习这个技术的之前,一定先从全局的角度来了解这个技术,思考一下它是由哪些模块构成的,提供了哪些功能,和同类的技术想必它有什么优势。
|
||||
|
||||
比如说我们在学习 Spring 的时候,通过 Spring 官方文档你就可以知道 Spring 最新的技术动态,Spring 包含哪些模块 以及 Spring 可以帮你解决什么问题。
|
||||
|
||||

|
||||
|
||||
再比如说我在学习消息队列的时候,我会先去了解这个消息队列一般在系统中有什么作用,帮助我们解决了什么问题。消息队列的种类很多,具体学习研究某个消息队列的时候,我会将其和自己已经学习过的消息队列作比较。像我自己在学习 RocketMQ 的时候,就会先将其和自己曾经学习过的第 1 个消息队列 ActiveMQ 进行比较,思考 RocketMQ 相对于 ActiveMQ 有了哪些提升,解决了 ActiveMQ 的哪些痛点,两者有哪些相似的地方,又有哪些不同的地方。
|
||||
|
||||
**学习一个技术最有效最快的办法就是将这个技术和自己之前学到的技术建立连接,形成一个网络。**
|
||||
|
||||
然后,我建议你先去看看官方文档的教程,运行一下相关的 Demo ,做一些小项目。
|
||||
|
||||
不过,官方文档通常是英文的,通常只有国产项目以及少部分国外的项目提供了中文文档。并且,官方文档介绍的往往也比较粗糙,不太适合初学者作为学习资料。
|
||||
|
||||
如果你看不太懂官网的文档,你也可以搜索相关的关键词找一些高质量的博客或者视频来看。 **一定不要一上来就想着要搞懂这个技术的原理。**
|
||||
|
||||
就比如说我们在学习 Spring 框架的时候,我建议你在搞懂 Spring 框架所解决的问题之后,不是直接去开始研究 Spring 框架的原理或者源码,而是先实际去体验一下 Spring 框架提供的核心功能 IoC(Inverse of Control:控制反转) 和 AOP(Aspect-Oriented Programming:面向切面编程),使用 Spring 框架写一些 Demo,甚至是使用 Spring 框架做一些小项目。
|
||||
|
||||
一言以蔽之, **在研究这个技术的原理之前,先要搞懂这个技术是怎么使用的。**
|
||||
|
||||
这样的循序渐进的学习过程,可以逐渐帮你建立学习的快感,获得即时的成就感,避免直接研究原理性的知识而被劝退。
|
||||
|
||||
**研究某个技术原理的时候,为了避免内容过于抽象,我们同样可以动手实践。**
|
||||
|
||||
比如说我们学习 Tomcat 原理的时候,我们发现 Tomcat 的自定义线程池挺有意思,那我们自己也可以手写一个定制版的线程池。再比如我们学习 Dubbo 原理的时候,可以自己动手造一个简易版的 RPC 框架。
|
||||
|
||||
另外,学习项目中需要用到的技术和面试中需要用到的技术其实还是有一些差别的。
|
||||
|
||||
如果你学习某一项技术是为了在实际项目中使用的话,那你的侧重点就是学习这项技术的使用以及最佳实践,了解这项技术在使用过程中可能会遇到的问题。你的最终目标就是这项技术为项目带来了实际的效果,并且,这个效果是正面的。
|
||||
|
||||
如果你学习某一项技术仅仅是为了面试的话,那你的侧重点就应该放在这项技术在面试中最常见的一些问题上,也就是我们常说的八股文。
|
||||
|
||||
很多人一提到八股文,就是一脸不屑。在我看来,如果你不是死记硬背八股文,而是去所思考这些面试题的本质。那你在准备八股文的过程中,同样也能让你加深对这项技术的了解。
|
||||
|
||||
最后,最重要同时也是最难的还是 **知行合一!知行合一!知行合一!** 不论是编程还是其他领域,最重要不是你知道的有多少,而是要尽量做到知行合一。
|
||||
|
@ -2,10 +2,11 @@
|
||||
|
||||
<!-- @include: @small-advertisement.snippet.md -->
|
||||
|
||||
这里主要会收录一些我看到的和程序员密切相关的非技术类的优质文章,每一篇都值得你阅读 3 遍以上!常看常新!
|
||||
这里主要会收录一些我看到的或者我自己写的和程序员密切相关的非技术类的优质文章,每一篇都值得你阅读 3 遍以上!常看常新!
|
||||
|
||||
## 练级攻略
|
||||
|
||||
- [程序员如何快速学习新技术](./advanced-programmer/programmer-quickly-learn-new-technology.md)
|
||||
- [程序员的技术成长战略](./advanced-programmer/the-growth-strategy-of-the-technological-giant.md)
|
||||
- [十年大厂成长之路](./advanced-programmer/ten-years-of-dachang-growth-road.md)
|
||||
- [给想成长为高级别开发同学的七条建议](./advanced-programmer/seven-tips-for-becoming-an-advanced-programmer.md)
|
||||
|
@ -647,7 +647,7 @@ System.out.println(aa==bb);// true
|
||||
|
||||
会创建 1 或 2 个字符串对象。
|
||||
|
||||
1、如果字符串常量池中不存在字符串对象“abc”的引用,那么它将首先在字符串常量池中创建,然后在堆空间中创建,因此将创建总共 2 个字符串对象。
|
||||
1、如果字符串常量池中不存在字符串对象“abc”的引用,那么它会在堆上创建两个字符串对象,其中一个字符串对象的引用会被保存在字符串常量池中。
|
||||
|
||||
示例代码(JDK 1.8):
|
||||
|
||||
|
@ -24,6 +24,10 @@ icon: codelibrary-fill
|
||||
- [excel-streaming-reader](https://github.com/monitorjbl/excel-streaming-reader):Excel 流式代码风格读取工具(只支持读取 XLSX 文件),基于 Apache POI 封装,同时保留标准 POI API 的语法。
|
||||
- [myexcel](https://github.com/liaochong/myexcel):一个集导入、导出、加密 Excel 等多项功能的工具包。
|
||||
|
||||
### Word
|
||||
|
||||
- [poi-tl](https://github.com/Sayi/poi-tl):基于 Apache POI 的 Word 模板引擎,可以根据 Word 模板和数据生成 Word 文档,所见即所得!
|
||||
|
||||
### JSON
|
||||
|
||||
- [JsonPath](https://github.com/json-path/JsonPath):处理 JSON 数据的工具库。
|
||||
|
@ -176,7 +176,7 @@ Kafka、Dubbo、ZooKeeper、Netty、Caffeine、Akka 中都有对时间轮的实
|
||||
|
||||

|
||||
|
||||
上图的时间轮,第 1 层的时间精度为 1 ,第 2 层的时间精度为 20 ,第 3 层的时间精度为 400。假如我们需要添加一个 350s 后执行的任务 A 的话(当前时间是 0s),这个任务会被放在第 2 层(因为第二层的时间跨度为 20\*20=400>350)的第 350/20=17 个时间格子。
|
||||
上图的时间轮(ms -> s),第 1 层的时间精度为 1 ,第 2 层的时间精度为 20 ,第 3 层的时间精度为 400。假如我们需要添加一个 350s 后执行的任务 A 的话(当前时间是 0s),这个任务会被放在第 2 层(因为第二层的时间跨度为 20\*20=400>350)的第 350/20=17 个时间格子。
|
||||
|
||||
当第一层转了 17 圈之后,时间过去了 340s ,第 2 层的指针此时来到第 17 个时间格子。此时,第 2 层第 17 个格子的任务会被移动到第 1 层。
|
||||
|
||||
|