推荐用std::partition原地分隔正负数:条件x>0使正数在前、非正数(0和负数)在后,时间复杂度O(n);需0归负数侧则用x>0,归正数侧则用x>=0;要求保持各自内部顺序时改用std::stable_partition。

用 std::partition 一次性分隔正负数(推荐)
最直接的办法不是手写循环,而是用标准库的 std::partition —— 它原地重排容器,把满足条件的元素全挪到前面,时间复杂度 O(n),且稳定(不保证相对顺序,但够用)。
注意:默认习惯是“非负数在前、负数在后”,但你要的是“正数在前、负数在后”,得小心 0 的归属。如果明确要 0 归入负数侧,判断条件写 x > 0;若想把 0 和正数一起放前面,就用 x >= 0。
示例:
int arr[] = {-3, 0, 5, -1, 2, -7};
int n = sizeof(arr) / sizeof(arr[0]);
auto pivot = std::partition(arr, arr + n, [](int x) { return x > 0; });
// 此时 [arr, pivot) 是正数,[pivot, arr+n) 是非正数(0 和负数)
- 必须包含
<algorithm> -
std::partition修改原数组,不额外分配内存 - 返回迭代器指向第一个不满足条件的元素位置,可用来切分
用 std::stable_partition 保持正数/负数内部顺序
如果你需要正数之间、负数之间的原始相对顺序不变(比如输入是 {-2, 3, -1, 4},希望输出正数侧仍是 3, 4、负数侧仍是 -2, -1),就得换 std::stable_partition。
立即学习“C++免费学习笔记(深入)”;
它比 std::partition 稍慢(通常 O(n log n) 或 O(n) 额外空间),但语义更可控。
- 仅多改一个函数名:
std::stable_partition - 同样支持 lambda 判断,
0的处理逻辑完全一致 - 对小数组(
手动双指针法(避免 STL 依赖或需精细控制)
当不能用 STL、或需要把结果分别存进两个新数组时,双指针最直观。但要注意边界和越界风险。
常见错误:用 while (i + 交换,却没跳过非目标值;或把 <code>0 当作正数处理导致逻辑错位。
- 推荐用两个独立索引:一个扫原数组,一个记正数插入位置,另一个记负数插入位置
- 别在原地交换时假设“左边一定有负数可换”——可能全是正数,
j会越界 - 如果目标是分离而非原地重排,直接开两个
std::vector分别push_back更安全
注意 0 和整型溢出带来的隐性 bug
很多实现默认把 0 当作“非正”,但业务需求可能不同。更隐蔽的问题是:如果数组含 INT_MIN,某些误写的判断(如 -x > 0)会溢出,触发未定义行为。
- 永远用
x > 0或x 判断,不要对负数取反再比较 - 如果需求文档写的是“非负数与负数分离”,那就用
x >= 0,别靠经验猜 - 用
std::vector<int>替代裸数组时,记得传.data()给std::partition,别传vec本身
实际项目里,std::partition 或 std::stable_partition 覆盖了绝大多数场景;真正要自己撸双指针,往往是因为得同时做统计、去重或配合其他约束——这时候,先写清楚 0 归哪边,比优化两行代码重要得多。


















