简单经典排序可逐步演示引导学习
冒泡排序
相邻比较与交换
相邻两个元素逆序就交换,一轮下来当前最大的元素会"冒"到未排序区间的末尾。
时间复杂度 O(n²);当前实现即使已排序也会扫完所有轮次(加 swapped 标记可提前结束)空间复杂度 O(1)
题目描述
给定一个整数数组 nums,使用冒泡排序把它原地升序排列:每一轮从左到右扫描,只要相邻两个数逆序就交换它们;每轮结束后,当前未排序部分中最大的数会"浮"到末尾。
学习目标
能说清冒泡排序每一轮锁定了哪个位置、循环边界为什么这样写,并能解释当前实现的复杂度。
已完成 0 / 6 阶段
诊断
先问:一轮结束谁就位了
冒泡排序每完成一轮,哪个位置一定已经排好?为什么不是最前面?
第 1 轮结束后,哪个位置一定就位?
建议先完成当前阶段(提示 / 检查 / 自评),再进入下一步;也可以直接跳过。
解题思路
核心思想
相邻两个元素逆序就交换,一轮下来当前最大的元素会"冒"到未排序区间的末尾。
为什么需要它
交换是排序能做的最小动作——只要能保证每次交换都让数组变得更有序,重复足够多次就能排好。问题是"更有序"这件事必须能被验证,否则算法不知道何时停、也不知道对不对。
第一反应:直觉方案
想排序,可以每轮找出最小值放到最前面(选择排序的思路)。但"找最小值"需要先扫描完整个未排序区间才能确定,一轮只安放一个位置。
关键洞察
换个视角:不需要"找最小值"这种全局信息。只要相邻两两比较、逆序就交换,最大值会像气泡一样一站站向右浮到末尾。更妙的是每轮结束都有一个必然成立的结论——末尾那个位置就是当前未排序部分的最大值,已经到达最终位置,下一轮不用再看它。未排序区间每轮缩小一格,这就是算法必然收敛的保证。
时间复杂度 O(n²);当前实现即使已排序也会扫完所有轮次(加 swapped 标记可提前结束)空间复杂度 O(1)
易错点
- 内层循环边界是 n - 1 - i,每轮少扫一个位置;写成固定的 n - 1 会把已排好的部分再次打乱
- 外层只需要 n - 1 轮:最后一个元素自然就位
- 死记两重循环容易写错边界,理解"每轮锁定一个位置"就不会错
逐步演示
参考代码
1function bubbleSort(nums) {
2 const n = nums.length;
3 for (let i = 0; i < n - 1; i++) {
4 for (let j = 0; j < n - 1 - i; j++) {
5 if (nums[j] > nums[j + 1]) {
6 [nums[j], nums[j + 1]] = [nums[j + 1], nums[j]];
7 }
8 }
9 }
10 return nums;
11}
效果图
预测:答对 0 / 共 1 题
第 1 / 34 步