Skip to content

Commit 6db8743

Browse files
committed
update: 排序算法和Spring面试题完善
1 parent 578115c commit 6db8743

File tree

2 files changed

+29
-19
lines changed

2 files changed

+29
-19
lines changed

docs/cs-basics/algorithms/10-classical-sorting-algorithms.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,9 +357,14 @@ public static int[] merge(int[] arr_1, int[] arr_2) {
357357

358358
快速排序使用[分治法](https://zh.wikipedia.org/wiki/分治法)(Divide and conquer)策略来把一个序列分为较小和较大的 2 个子序列,然后递归地排序两个子序列。具体算法描述如下:
359359

360-
1. 从序列中**随机**挑出一个元素,做为 “基准”(`pivot`);
361-
2. 重新排列序列,将所有比基准值小的元素摆放在基准前面,所有比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个操作结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
362-
3. 递归地把小于基准值元素的子序列和大于基准值元素的子序列进行快速排序。
360+
1. **选择基准(Pivot)** :从数组中选一个元素作为基准。为了避免最坏情况,通常会随机选择。
361+
2. **分区(Partition)** :重新排列序列,将所有比基准值小的元素摆放在基准前面,所有比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个操作结束之后,该基准就处于数列的中间位置。
362+
3. **递归(Recurse)** :递归地把小于基准值元素的子序列和大于基准值元素的子序列进行快速排序。
363+
364+
**关于性能,这也是它与归并排序的关键区别:**
365+
366+
- **平均和最佳情况:** 它的时间复杂度是 $O(nlogn)$。这种情况发生在每次分区都能把数组分成均等的两半。
367+
- **最坏情况:** 它的时间复杂度会退化到 $O(n^2)$。这发生在每次我们选的基准都是当前数组的最小值或最大值时,比如对一个已经排好序的数组,每次都选第一个元素做基准,这就会导致分区极其不均,算法退化成类似冒泡排序。这就是为什么**随机选择基准**非常重要。
363368

364369
### 图解算法
365370

docs/system-design/framework/spring/spring-knowledge-and-questions-summary.md

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -232,37 +232,40 @@ Spring 内置的 `@Autowired` 以及 JDK 内置的 `@Resource` 和 `@Inject` 都
232232

233233
### @Autowired@Resource 的区别是什么?
234234

235-
`Autowired` 属于 Spring 内置的注解,默认的注入方式为`byType`(根据类型进行匹配),也就是说会优先根据接口类型去匹配并注入 Bean (接口的实现类)
235+
`@Autowired` Spring 内置的注解,默认注入逻辑为**先按类型(byType)匹配,若存在多个同类型 Bean,则再尝试按名称(byName)筛选**
236236

237-
**这会有什么问题呢?** 当一个接口存在多个实现类的话,`byType`这种方式就无法正确注入对象了,因为这个时候 Spring 会同时找到多个满足条件的选择,默认情况下它自己不知道选择哪一个。
237+
具体来说:
238238

239-
这种情况下,注入方式会变为 `byName`(根据名称进行匹配),这个名称通常就是类名(首字母小写)。就比如说下面代码中的 `smsService` 就是我这里所说的名称,这样应该比较好理解了吧。
239+
1. 优先根据接口 / 类的类型在 Spring 容器中查找匹配的 Bean。若只找到一个符合类型的 Bean,直接注入,无需考虑名称;
240+
2. 若找到多个同类型的 Bean(例如一个接口有多个实现类),则会尝试通过**属性名或参数名**与 Bean 的名称进行匹配(默认 Bean 名称为类名首字母小写,除非通过 `@Bean(name = "...")``@Component("...")` 显式指定)。
240241

241-
```java
242-
// smsService 就是我们上面所说的名称
243-
@Autowired
244-
private SmsService smsService;
245-
```
242+
当一个接口存在多个实现类时:
243+
244+
- 若属性名与某个 Bean 的名称一致,则注入该 Bean;
245+
- 若属性名与所有 Bean 名称都不匹配,会抛出 `NoUniqueBeanDefinitionException`,此时需要通过 `@Qualifier` 显式指定要注入的 Bean 名称。
246246

247-
举个例子,`SmsService` 接口有两个实现类: `SmsServiceImpl1``SmsServiceImpl2`,且它们都已经被 Spring 容器所管理。
247+
举例说明:
248248

249249
```java
250-
// 报错,byName 和 byType 都无法匹配到 bean
250+
// SmsService 接口有两个实现类:SmsServiceImpl1、SmsServiceImpl2(均被 Spring 管理)
251+
252+
// 报错:byType 匹配到多个 Bean,且属性名 "smsService" 与两个实现类的默认名称(smsServiceImpl1、smsServiceImpl2)都不匹配
251253
@Autowired
252254
private SmsService smsService;
253-
// 正确注入 SmsServiceImpl1 对象对应的 bean
255+
256+
// 正确:属性名 "smsServiceImpl1" 与实现类 SmsServiceImpl1 的默认名称匹配
254257
@Autowired
255258
private SmsService smsServiceImpl1;
256-
// 正确注入 SmsServiceImpl1 对象对应的 bean
257-
// smsServiceImpl1 就是我们上面所说的名称
259+
260+
// 正确:通过 @Qualifier 显式指定 Bean 名称 "smsServiceImpl1"
258261
@Autowired
259262
@Qualifier(value = "smsServiceImpl1")
260263
private SmsService smsService;
261264
```
262265

263-
我们还是建议通过 `@Qualifier` 注解来显式指定名称而不是依赖变量的名称。
266+
实际开发实践中,我们还是建议通过 `@Qualifier` 注解来显式指定名称而不是依赖变量的名称。
264267

265-
`@Resource`属于 JDK 提供的注解,默认注入方式为 `byName`。如果无法通过名称匹配到对应的 Bean 的话,注入方式会变为`byType`
268+
`@Resource`属于 JDK 提供的注解,默认注入逻辑为**先按名称(byName)匹配,若存在多个同类型 Bean,则再尝试按类型(byType)筛选**
266269

267270
`@Resource` 有两个比较重要且日常开发常用的属性:`name`(名称)、`type`(类型)。
268271

@@ -287,13 +290,15 @@ private SmsService smsServiceImpl1;
287290
private SmsService smsService;
288291
```
289292

290-
简单总结一下:
293+
**简单总结一下**
291294

292295
- `@Autowired` 是 Spring 提供的注解,`@Resource` 是 JDK 提供的注解。
293296
- `Autowired` 默认的注入方式为`byType`(根据类型进行匹配),`@Resource`默认注入方式为 `byName`(根据名称进行匹配)。
294297
- 当一个接口存在多个实现类的情况下,`@Autowired``@Resource`都需要通过名称才能正确匹配到对应的 Bean。`Autowired` 可以通过 `@Qualifier` 注解来显式指定名称,`@Resource`可以通过 `name` 属性来显式指定名称。
295298
- `@Autowired` 支持在构造函数、方法、字段和参数上使用。`@Resource` 主要用于字段和方法上的注入,不支持在构造函数或参数上使用。
296299

300+
考虑到 `@Resource` 的语义更清晰(名称优先),并且是 Java 标准,能减少对 Spring 框架的强耦合,我们通常**更推荐使用 `@Resource`**,尤其是在需要按名称注入的场景下。而 `@Autowired` 配合构造器注入,在实现依赖注入的不可变性和强制性方面有优势,也是一种非常好的实践。
301+
297302
### 注入 Bean 的方式有哪些?
298303

299304
依赖注入 (Dependency Injection, DI) 的常见方式:

0 commit comments

Comments
 (0)