核心结论:
- 选择排序:找「最小 / 最大元素」,放到已排序区末尾(主打 “找了再换”);
一、排序的核心概念(零基础必看)
以升序排序为例,把数组分成两部分:
- 已排序区间:初始为空,排好序的元素都在这里;
- 待排序区间:初始是整个数组,需要处理的元素都在这里。排序的本质就是不断缩小(待排序区间),直到它为空。
二、选择排序(Selection Sort):找最小的,缓过来
核心逻辑
比如要排序数组 [64, 25, 12, 22, 11],步骤像 “选班干部”:
1.第一轮:在整个数组里找最小的数(11),和第一个位置的64交换[11,25,12,22,64] (已排序区域:[11]);
2.第二轮:在剩下的[25,12,22,64]里找最小的数(12),和第二个位置的25交换 [11,12,25,22,64] (已排序区域:[11,12]);
3.第三轮:在剩下的 [25,22,64] 里找最小的数(22),和第三个位置的25交换 [11,12,22,25,64] (已排序区域:[11,12,22]);
4.第四轮:在剩下的 [25,64] 里找最小的数 (25),和第四个位置的25交换,最后完成排序。
总结:每轮只做“一次交换”,先找最小元素的位置,再交换
import java.until.Arrays;//用来打印数组,方便看结果
public class SelectionSort {
//选择排序方法:传入待排序数组,返回排序后的新数组
public static int[] selectionSort(int[] originalArr) {
//1.复制原数组,避免修改原数组(新手记住:Arrays.copyOf是数组复制)
int[] arr = Arrays.copyOf(originalArr,originalArr.length);
//2.获取数组长度,n = 5(对应例子里的)
int n = arr.length;
//3.外层循环:控制“已排序区域”的末尾位置(i是待排序区域的第一个位置)
//循环n-1次啊即可:因为最后1个元素不用比,前面排好它自然再正确位置
for(int i = 0; i < n - 1 ; i++) {
//初始化:加上当前待排序区的第一个元素是最小值,记录它的索引
int minIndex = i;
//4.内层循环:遍历待排序区域,找真正的最小值的索引
//j从i+1开始(因为i已经是假设的最小值,不用和自己比)
for(int j = i + 1; j <n ; j++ ) {
//如果发现比当前值更小的数,更新最小值的索引
if(arr[j] < arr[minIndex]) {
minIndex = j;
}
}
5.交换:把找到的最小值,和待排序区域的第一个元素(arr[i])交换
//临时遍历temp:用来存交换的中间值(Java里不能直接a = b; b = a;)
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
//打印每轮结果,只管看到排序过程
System.out.println("第" + (i+1) + "轮排序后:" + Arrays.toString(arr));
}
}
// 6. 返回排序后的数组
return arr;
}
// 主方法:测试排序
public static void main(String[] args) {
// 测试数组
int[] testArr = {64, 25, 12, 22, 11};
// 调用排序方法
int[] sortedArr = selectionSort(testArr);
// 打印最终结果
System.out.println("最终排序结果:" + Arrays.toString(sortedArr));
}
新手易错点
- 内层循环
j从i+1开始,不是从 0 开始(否则会重复比较已排序区); - 交换时必须用临时变量
temp,直接arr[i] = arr[minIndex]; arr[minIndex] = arr[i]会导致两个位置的值都变成同一个数; - 选择排序是「不稳定排序」:比如数组
[2, 2, 1],第一轮交换后会变成[1, 2, 2],虽然结果对,但两个 2 的相对位置变了(新手暂时记结论即可)。