🎯 题目要求
编写一个函数 f(int a[])
,该函数接收一个有序数组,并将其元素原地倒序存储 —— 即第一个元素与最后一个交换,第二个与倒数第二个交换,以此类推。
在 main()
函数中:
- 定义数组
int b[5] = {1, 2, 3, 4, 5};
- 调用函数
f(b);
- 输出倒序后的数组内容
⚠️ 关键限制:函数中不允许定义额外数组,必须在原数组内完成倒序操作!
💡 解题思路
这是一个经典的“双指针原地交换”问题:
- 设置两个指针(或索引):
left
从数组开头(索引 0)开始right
从数组末尾(索引len-1
)开始
- 交换
a[left]
与a[right]
left++
,right--
- 重复直到
left >= right
这样可以在 O(n/2) 时间内完成倒序,空间复杂度为 O(1),完美符合“原地操作”要求。
✅ 完整代码实现
#include <stdio.h>
// 函数声明:原地倒序数组
void f(int a[], int len);
int main() {
// 定义并初始化数组
int b[5] = {1, 2, 3, 4, 5};
int i;
printf("原数组: ");
for (i = 0; i < 5; i++) {
printf("%d ", b[i]);
}
printf("\n");
// 调用函数倒序
f(b, 5);
printf("倒序后: ");
for (i = 0; i < 5; i++) {
printf("%d ", b[i]);
}
printf("\n");
return 0;
}
// 函数定义:原地倒序数组元素
void f(int a[], int len) {
int left = 0;
int right = len - 1;
int temp;
// 双指针交换直到相遇
while (left < right) {
// 交换元素
temp = a[left];
a[left] = a[right];
a[right] = temp;
// 移动指针
left++;
right--;
}
}
🧪 运行结果
原数组: 1 2 3 4 5
倒序后: 5 4 3 2 1
✅ 完全符合题目要求!
🧠 知识点解析
1. 数组作为函数参数的本质是“指针”
在 C 语言中,void f(int a[])
和 void f(int *a)
是等价的 —— 数组名在传参时退化为指向首元素的指针。因此,函数内部对 a[]
的修改会直接影响原数组 b
。
2. 原地操作(In-place Algorithm)
- 优点:节省内存,无需额外空间。
- 核心思想:利用变量交换 + 双指针技巧。
- 适用场景:数组翻转、字符串逆序、部分排序等。
3. 边界控制
循环条件 while (left < right)
确保:
- 偶数长度数组:指针在中间“擦肩而过”
- 奇数长度数组:指针在正中间元素“相遇”停止
→ 中间元素无需交换,位置不变。
🚀 扩展思考
你可以尝试以下变体练习:
- 使用递归实现倒序
- 不使用临时变量交换(异或技巧)
a[left] ^= a[right]; a[right] ^= a[left]; a[left] ^= a[right];
- 倒序字符串
- 倒序二维数组的每一行
📌 总结
本题虽然简单,但涵盖了 C 语言中几个核心概念:
- ✅ 数组与指针的等价性
- ✅ 函数传参的“地址传递”特性
- ✅ 双指针算法思想
- ✅ 原地操作的内存效率
掌握这类基础题型,对后续学习数据结构(如链表反转、栈操作等)大有裨益!
💬 互动提问:你还能想到哪些“原地操作”的经典算法?欢迎在评论区分享交流!
📌 收藏 + 关注,持续更新 C 语言、数据结构与算法实战内容!