瀏覽代碼

feat: 新增Demo05选择排序代码及笔记更新

- 新增Demo05.java(选择排序实现)
- 更新20260716笔记:新增选择排序章节(思路图解、代码实现、冒泡vs选择对比)
- 更新完整代码汇总新增Demo05.java代码
- 补充随堂练习要点(选择排序相关要点)
- 补充拓展阅读(选择排序概念及复杂度)
WanJL 2 天之前
父節點
當前提交
7a5119704c
共有 2 個文件被更改,包括 236 次插入17 次删除
  1. 44 0
      授课代码/c260716/src/Demo05.java
  2. 192 17
      课堂笔记/01-JavaSE基础-笔记/20260716-笔记.md

+ 44 - 0
授课代码/c260716/src/Demo05.java

@@ -0,0 +1,44 @@
+import java.util.Arrays;
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Demo05
+ * @description 数组排序-选择排序
+ * @create 2026/7/16
+ */
+public class Demo05 {
+    /*
+        选择排序:
+        选择排序的思路要比冒泡排序更聪明一点,冒泡排序是不断的交换相邻的元素,而选择排序,是每轮只做一次交换。
+        选择的思路是 每一轮从剩余未排序的元素中找出最小的元素,直接把它放到未排序部分的第1位。
+        核心思路:每一轮从未排序区间选出最小值,与未排序区间的第1个元素进行交换。
+     */
+    public static void main(String[] args) {
+        /*
+            选择排序:每一轮从未排序区间选出最小值,放到已排序区间的末尾
+         */
+
+        int[] arr={1,456,782,5,8,4,598,1,46,68,465,74};
+        //外层循环:i 既是已排序区间的末尾边界,也是当前要确定的位置
+        for (int i = 0; i < arr.length-1; i++) {
+            //假设当前未排序区间的第1个元素就是最小的
+            int minIndex=i; //假设i就是最小的元素的索引值
+            //内层循环:在未排序区间[i+1,arr.length-1] 找到真正的最小值
+            for (int j = i+1; j <arr.length; j++) {
+                //判断谁才是最小值
+                if (arr[j]<arr[minIndex]){
+                    minIndex=j; //就更新最小元素的索引值
+                }
+            }   //当内层循环跑完一轮,就得到了数组的最小元素索引值
+            // 如果得到的最小元素索引值 minIndex 和 当前的 i 不想等,
+            //那就交换位置
+            if (minIndex!=i){
+                arr[minIndex]=arr[minIndex]+arr[i];
+                arr[i]=arr[minIndex]-arr[i];
+                arr[minIndex]=arr[minIndex]-arr[i];
+            }
+            System.out.println("第"+(i+1)+"轮选择后:"+ Arrays.toString(arr));
+        }
+    }
+}

+ 192 - 17
课堂笔记/01-JavaSE基础-笔记/20260716-笔记.md

@@ -322,7 +322,122 @@ for (int i = 0; i < arr2.length - 1; i++) {
 
 ---
 
-## 五、课堂练习详解
+## 五、选择排序(Selection Sort)
+
+### 1. 选择排序概述
+
+**选择排序**的思路比冒泡排序更"聪明"——冒泡排序是不断交换相邻元素,而选择排序**每轮只做一次交换**。
+
+#### 核心思想
+
+> 每一轮从**剩余未排序的元素**中找出**最小的元素**,直接把它放到**未排序部分的第 1 位**(即已排序区间的末尾)。
+
+#### 算法步骤图解
+
+以数组 `{29, 10, 14, 37, 13}` 为例,从小到大排序:
+
+```
+第1轮(i=0):在 [0, 4] 找最小值 10,与 arr[0]=29 交换
+  [29, 10, 14, 37, 13] → 找到最小值 10 (索引 1)
+  → 交换 → [10, 29, 14, 37, 13]  ← 10 到位
+
+第2轮(i=1):在 [1, 4] 找最小值 13,与 arr[1]=29 交换
+  [10, 29, 14, 37, 13] → 找到最小值 13 (索引 4)
+  → 交换 → [10, 13, 14, 37, 29]  ← 13 到位
+
+第3轮(i=2):在 [2, 4] 找最小值 14,已在正确位置,不交换
+  [10, 13, 14, 37, 29] → 找到最小值 14 (索引 2)
+  → minIndex == i,不交换  ← 14 已在正确位置
+
+第4轮(i=3):在 [3, 4] 找最小值 29,与 arr[3]=37 交换
+  [10, 13, 14, 37, 29] → 找到最小值 29 (索引 4)
+  → 交换 → [10, 13, 14, 29, 37]  ← 29、37 到位
+
+排序完成 ✅
+```
+
+---
+
+### 2. 选择排序代码实现
+
+```java
+import java.util.Arrays;
+
+int[] arr = {1, 456, 782, 5, 8, 4, 598, 1, 46, 68, 465, 74};
+
+// 外层循环:i 既是已排序区间的末尾边界,也是当前要确定的位置
+for (int i = 0; i < arr.length - 1; i++) {
+    // 假设当前未排序区间的第 1 个元素就是最小的
+    int minIndex = i;  // 假设 i 就是最小元素的索引值
+    // 内层循环:在未排序区间 [i+1, arr.length-1] 找到真正的最小值
+    for (int j = i + 1; j < arr.length; j++) {
+        if (arr[j] < arr[minIndex]) {
+            minIndex = j;  // 更新最小元素的索引值
+        }
+    }
+    // 如果最小元素索引值 minIndex 和当前 i 不相等,就交换位置
+    if (minIndex != i) {
+        arr[minIndex] = arr[minIndex] + arr[i];
+        arr[i] = arr[minIndex] - arr[i];
+        arr[minIndex] = arr[minIndex] - arr[i];
+    }
+    System.out.println("第" + (i + 1) + "轮选择后:" + Arrays.toString(arr));
+}
+```
+
+**代码要点**:
+
+| 部分 | 说明 |
+|------|------|
+| **外层循环** `i` | 控制选择的轮数,`arr.length - 1` 轮;`i` 也是当前要确定的位置 |
+| **内层循环** `j` | 在**未排序区间** `[i+1, arr.length-1]` 中寻找最小值 |
+| **`minIndex`** | 记录当前找到的最小元素的索引值,初始为 `i` |
+| **交换条件** | 当 `minIndex != i` 时,说明最小值不在当前位置,需要交换 |
+| **每轮只交换一次** | 找到最小值后,直接与当前位置交换,比冒泡排序更高效 |
+
+---
+
+### 3. 冒泡排序 vs 选择排序对比
+
+| 特性 | 冒泡排序 | 选择排序 |
+|------|---------|---------|
+| **核心思路** | 相邻比较,大的往后冒 | 每轮选最小值,放到正确位置 |
+| **每轮交换次数** | 多次(可能每轮交换 n 次) | **最多 1 次** |
+| **比较次数** | 固定 O(n²/2) | 固定 O(n²/2) |
+| **时间复杂度(平均)** | O(n²) | O(n²) |
+| **时间复杂度(最好)** | O(n) — 优化版 | O(n²) — 仍要遍历全部 |
+| **时间复杂度(最坏)** | O(n²) | O(n²) |
+| **空间复杂度** | O(1) | O(1) |
+| **稳定性** | ✅ 稳定 | ❌ 不稳定 |
+| **适用场景** | 小规模数据、教学演示 | 小规模数据、交换成本高的场景 |
+
+> **稳定性说明**:选择排序是不稳定的,因为当最小值与前面的元素交换时,可能改变相等元素的相对顺序。例如 `[5, 5, 2]` → 第一轮将 `2` 与第一个 `5` 交换,两个 `5` 的相对顺序就变了。
+
+---
+
+### 4. 两种排序的过程对比
+
+以数组 `{5, 3, 8, 6, 4}` 为例:
+
+**冒泡排序**(每轮可能多次交换):
+```
+第1轮:5>3→交换, 5<8不换, 8>6→交换, 8>4→交换 → [3,5,6,4,8]
+第2轮:3<5不换, 5<6不换, 6>4→交换          → [3,5,4,6,8]
+第3轮:3<5不换, 5>4→交换                   → [3,4,5,6,8]
+第4轮:3<4不换                              → [3,4,5,6,8]
+```
+
+**选择排序**(每轮最多一次交换):
+```
+第1轮:找最小值 3 (索引1),与 arr[0]=5 交换  → [3,5,8,6,4]
+第2轮:找最小值 4 (索引4),与 arr[1]=5 交换  → [3,4,8,6,5]
+第3轮:找最小值 5 (索引4),与 arr[2]=8 交换  → [3,4,5,6,8]
+第4轮:找最小值 6 (索引3),已在正确位置不交换 → [3,4,5,6,8]
+```
+
+---
+
+## 六、课堂练习详解
 
 ### 练习 01:首尾对称交换数组元素
 
@@ -471,7 +586,7 @@ for (int i = 0; i < newArr.length; i++) {
 
 ---
 
-## 、课后作业讲解(7月15日作业)
+## 、课后作业讲解(7月15日作业)
 
 ### 作业 07:数组元素求和
 
@@ -559,7 +674,7 @@ System.out.println("奇数个数:" + count + ",偶数个数:" + (arr.lengt
 
 ---
 
-## 、随堂练习要点
+## 、随堂练习要点
 
 1. **多维数组本质**:数组的数组,二维数组的元素是一维数组的引用地址
 2. **二维数组定义**:`int[][] arr = new int[3][2];`(3 行 2 列)
@@ -577,21 +692,27 @@ System.out.println("奇数个数:" + count + ",偶数个数:" + (arr.lengt
 14. **冒泡排序-外层循环**:控制冒泡轮数,共 `arr.length - 1` 轮
 15. **冒泡排序-内层循环**:在未排序区间 `[0, arr.length-1-i]` 相邻比较
 16. **冒泡排序-优化**:引入 `boolean` 标记,本轮无交换则提前结束
-18. **变量交换-临时变量法**:`tmp = a; a = b; b = tmp;`
-19. **变量交换-加减法**:`a = a + b; b = a - b; a = a - b;`
-20. **首尾交换**:利用对称性,第 i 位与第 length-1-i 位交换
-21. **循环右移**:从后往前逐个移动,保存最后一个元素放到开头
-22. **取模优化**:`k = k % arr.length` 解决 k 大于数组长度的问题
-23. **数组去重思路**:统计不重复个数 → 创建新数组 → 填充不重复元素
-24. **布尔标记法**:使用 `boolean` 变量标记元素是否重复
-25. **打擂法找最大值**:假设第一个是最大值,遇到更大的就更新
-26. **数组求和**:遍历数组,累加每个元素
-27. **倒序输出**:从 `length-1` 到 `0` 递减遍历
-28. **奇偶判断**:`n % 2 == 0` 偶,`n % 2 != 0` 奇
+17. **选择排序**:每轮从未排序区间选出最小值,与未排序区间的第 1 个元素交换
+18. **选择排序-外层循环**:`i` 是当前要确定的位置,范围 `[0, arr.length-2]`
+19. **选择排序-内层循环**:在未排序区间 `[i+1, arr.length-1]` 找最小值索引
+20. **选择排序-minIndex**:记录最小元素的索引值,初始为 `i`
+21. **选择排序-交换条件**:`minIndex != i` 时才交换,每轮最多交换 1 次
+22. **选择排序 vs 冒泡排序**:选择排序每轮最多交换 1 次,冒泡排序可能交换多次
+23. **变量交换-临时变量法**:`tmp = a; a = b; b = tmp;`
+24. **变量交换-加减法**:`a = a + b; b = a - b; a = a - b;`
+25. **首尾交换**:利用对称性,第 i 位与第 length-1-i 位交换
+26. **循环右移**:从后往前逐个移动,保存最后一个元素放到开头
+27. **取模优化**:`k = k % arr.length` 解决 k 大于数组长度的问题
+28. **数组去重思路**:统计不重复个数 → 创建新数组 → 填充不重复元素
+29. **布尔标记法**:使用 `boolean` 变量标记元素是否重复
+30. **打擂法找最大值**:假设第一个是最大值,遇到更大的就更新
+31. **数组求和**:遍历数组,累加每个元素
+32. **倒序输出**:从 `length-1` 到 `0` 递减遍历
+33. **奇偶判断**:`n % 2 == 0` 偶,`n % 2 != 0` 奇
 
 ---
 
-## 八、知识拓展
+## 、知识拓展
 
 ### 1. 数组的地址值
 
@@ -650,7 +771,7 @@ System.out.println(a);  // 输出类似:[I@b4c966a
 
 ---
 
-## 、完整代码汇总
+## 、完整代码汇总
 
 ### Demo01.java — 多维数组
 
@@ -862,6 +983,51 @@ public class Demo04 {
 }
 ```
 
+### Demo05.java — 选择排序
+
+```java
+import java.util.Arrays;
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Demo05
+ * @description 数组排序-选择排序
+ * @create 2026/7/16
+ */
+public class Demo05 {
+    /*
+        选择排序:
+        选择排序的思路要比冒泡排序更聪明一点,冒泡排序是不断的交换相邻的元素,
+        而选择排序,是每轮只做一次交换。
+        选择的思路是每一轮从剩余未排序的元素中找出最小的元素,
+        直接把它放到未排序部分的第1位。
+        核心思路:每一轮从未排序区间选出最小值,与未排序区间的第1个元素进行交换。
+     */
+    public static void main(String[] args) {
+        int[] arr = {1, 456, 782, 5, 8, 4, 598, 1, 46, 68, 465, 74};
+        //外层循环:i 既是已排序区间的末尾边界,也是当前要确定的位置
+        for (int i = 0; i < arr.length - 1; i++) {
+            //假设当前未排序区间的第1个元素就是最小的
+            int minIndex = i;
+            //内层循环:在未排序区间 [i+1, arr.length-1] 找到真正的最小值
+            for (int j = i + 1; j < arr.length; j++) {
+                if (arr[j] < arr[minIndex]) {
+                    minIndex = j;  //更新最小元素的索引值
+                }
+            }
+            //如果最小元素索引值和当前 i 不相等,就交换位置
+            if (minIndex != i) {
+                arr[minIndex] = arr[minIndex] + arr[i];
+                arr[i] = arr[minIndex] - arr[i];
+                arr[minIndex] = arr[minIndex] - arr[i];
+            }
+            System.out.println("第" + (i + 1) + "轮选择后:" + Arrays.toString(arr));
+        }
+    }
+}
+```
+
 ### Exercises01.java — 首尾对称交换
 
 ```java
@@ -1084,7 +1250,7 @@ public class HomeWork10 {
 
 ---
 
-## 十、拓展阅读
+## 十、拓展阅读
 
 | 概念 | 说明 |
 |------|------|
@@ -1104,6 +1270,15 @@ public class HomeWork10 {
 | **冒泡排序-优化** | 引入 `boolean` 标记判断本轮是否有交换,无交换则提前结束排序 |
 | **冒泡排序-时间复杂度** | 平均 O(n²),最好 O(n)(优化版已有序),最坏 O(n²) |
 | **冒泡排序-空间复杂度** | O(1),原地排序,不需要额外空间 |
+| **选择排序** | 每轮从未排序区间选出最小值,与未排序区间的第 1 个元素交换,每轮最多 1 次交换 |
+| **选择排序-外层循环** | `i` 是当前要确定的位置,范围 `[0, arr.length-2]` |
+| **选择排序-内层循环** | 在未排序区间 `[i+1, arr.length-1]` 找最小值索引 |
+| **选择排序-minIndex** | 记录最小元素的索引值,初始为当前位置 `i`,遇更小值则更新 |
+| **选择排序-交换条件** | `minIndex != i` 时才执行交换,每轮最多交换 1 次 |
+| **选择排序-时间复杂度** | 平均 O(n²),最好 O(n²),最坏 O(n²) — 始终要遍历全部 |
+| **选择排序-空间复杂度** | O(1),原地排序 |
+| **选择排序-稳定性** | ❌ 不稳定(交换可能改变相等元素的相对顺序) |
+| **冒泡 vs 选择** | 冒泡多次交换,选择最多 1 次;冒泡稳定,选择不稳定 |
 | **变量交换-临时变量** | `tmp = a; a = b; b = tmp;` 最直观的交换方式 |
 | **变量交换-加减法** | `a = a + b; b = a - b; a = a - b;` 不借助第三个变量 |
 | **数组循环右移** | 从后往前逐位移动,保存最后一位到第一位,外层套循环控制移动次数 |