先把旧值保存好,
再从两端交换
今天从交换两个整数开始,把同一套方法用到数组元素上,再让左右下标自动向中间移动,完成真正的数组反转。
连续赋值为什么不能完成交换
如果 a 原来是 3、b 原来是 8,先执行 a = b,a 的旧值 3 就被覆盖了。接着执行 b = a,只能再次把 8 赋给 b,最终两个变量都是 8。
预测这段代码时,我最初把赋值前的状态当成第一步执行后的状态。重新逐句追踪后确认:赋值会覆盖左侧变量原来的值,必须在覆盖前把旧值保存下来。
int a = 3;
int b = 8;
int temp = a;
a = b;
b = temp;
printf("交换后:a = %d,b = %d\n", a, b);temp 保存 a 原来的 3;a 再接收 b 的 8;最后 b 从 temp 取回 3。实际运行正确输出“交换后:a = 8,b = 3”。
交换数组两端的元素
交换数组元素时,方法没有改变,只是把普通变量换成带下标的元素。数组 {10,20,30,40} 交换下标 0 和 3 后,得到 {40,20,30,10}。
这里交换的是 values 中的数据,left 和 right 本身并没有互换;它们随后分别加 1、减 1,只负责指向下一对需要处理的位置。
从两端向中间完成原地反转
int values[5] = {1, 2, 3, 4, 5};
size_t count = sizeof(values) / sizeof(values[0]);
size_t left = 0;
size_t right = count - 1;
while (left < right)
{
int swap_temp = values[left];
values[left] = values[right];
values[right] = swap_temp;
left++;
right--;
}数组从下标 0 开始,所以最后一个合法下标是 count - 1。条件使用 left < right:奇数长度数组走到中间时 left 与 right 相等,中间元素不需要和自己交换。
奇数、偶数和单元素边界
- 五个元素交换下标 0↔4、1↔3,共 2 对,中间下标 2 不动。
- 六个元素交换下标 0↔5、1↔4、2↔3,共 3 对。
- 单元素数组开始时 left 与 right 都是 0,条件不成立,循环不会执行。
预测偶数数组时,我曾漏掉中间的 2↔3,把只完成两次交换的中间状态当作最终结果。补上第三对后,{10,20,30,40,50,60} 正确反转为 {60,50,40,30,20,10}。
倒序输出不等于原地反转
从最后一个下标开始倒着读取,可以在屏幕上显示反序,但数组内部没有改变。原地反转则真正交换元素;交换结束后,即使从下标 0 正常遍历,也会得到反转后的顺序。
独立练习:发现相似变量混用
独立练习使用数组 {3,6,9,12,15,18,21}。第一次运行只输出六个元素,反转结果也不正确。检查后发现,新的 numbers 数组误用了上一段代码的 count 和 right。
两处输出循环应使用 numbers 对应的 countt;交换右侧元素也应写成 numbers[rightt]。旧的 right 属于 values,并且前一个循环结束后已经是 2,误用它会反复写入 numbers[2]。
修正三处变量后,程序正确输出:
反转前:3 6 9 12 15 18 21
反转后:21 18 15 12 9 6 3最后还修正了输出文字中“练习”的笔误。今天的代码均正常退出;通过这次调试,我进一步确认:多个数组出现在同一程序中时,要特别注意每个数组对应的长度和左右下标。
下一课从相邻元素比较开始,把今天的交换操作用于一次冒泡,再逐步完成数组升序排序。