You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C语言中用O(n)算法原地划分整数数组(负数左正数右)

线性时间原地划分整数数组:负数左、正数右

你提到的双指针思路本身完全可以实现**O(n)**的线性时间复杂度,但你当前的实现因为嵌套了两层循环,才变成了O(n²)。咱们可以简化逻辑,要么一次遍历完成,要么调整双指针的移动方式,避免嵌套循环,都能高效完成划分。

先看看你原来的实现代码:

int* swaps(int* array){ 
    int* ptr1; 
    ptr1 = &array[0]; 
    int* ptr2; 
    ptr2 = &array[N-1]; 
    int tmp; 
    for(ptr1; ptr1 <= &array[N-1]; ptr1++){ 
        if(ptr1==ptr2){ 
            return array; 
        } 
        if(*ptr1 >= 0){ 
            for(ptr2; ptr2 >= &array[0]; ptr2--){ 
                if(ptr1==ptr2){ 
                    return array; 
                } 
                // swap elements 
                if(*ptr2 < 0){ 
                    tmp = *ptr2; 
                    *ptr2 = *ptr1; 
                    *ptr1 = tmp; 
                    ptr2--; 
                    if(ptr1==ptr2){ 
                        return array; 
                    } 
                    break; 
                } 
            } 
        } 
    } 
}

这个实现的问题在于:当左指针ptr1遇到正数时,会启动一个从右往左的嵌套循环找负数,最坏情况下(比如数组全是正数),每个左指针位置都要遍历整个右半部分,时间复杂度直接变成了O(n²)。

优化方案1:单遍历的双指针实现

这个思路更简洁:用一个指针left标记下一个负数应该放置的位置,另一个指针right遍历整个数组,遇到负数就和left位置的元素交换,然后left右移。整个过程只遍历数组一次,时间复杂度O(n),空间复杂度O(1)。

void partitionNegativesLeft(int* array, int n) {
    int left = 0; // 标记下一个负数要存放的位置
    for (int right = 0; right < n; right++) {
        if (array[right] < 0) {
            // 交换当前负数到left位置
            int tmp = array[left];
            array[left] = array[right];
            array[right] = tmp;
            left++;
        }
    }
}

优化方案2:左右向中间逼近的双指针实现

如果你更偏好左右指针向中间移动的思路,也可以调整逻辑,避免嵌套循环,同样实现O(n)时间:

void partitionNegativesLeftTwoPointers(int* array, int n) {
    int left = 0;
    int right = n - 1;
    while (left < right) {
        // 左指针找到第一个正数
        while (left < right && array[left] < 0) {
            left++;
        }
        // 右指针找到第一个负数
        while (left < right && array[right] >= 0) {
            right--;
        }
        // 交换两者,然后指针向中间移动
        if (left < right) {
            int tmp = array[left];
            array[left] = array[right];
            array[right] = tmp;
            left++;
            right--;
        }
    }
}

这里的两个内部while循环不会重复遍历元素,因为每个指针只会向中间移动,不会回头,所以整体还是线性时间复杂度,比你原来的嵌套循环简洁高效得多。

补充说明

  • 两种实现都不会对负数或正数内部进行排序,只是完成“负数左、正数右”的划分,完全符合你的需求。
  • 都是原地操作,不需要额外辅助数组,空间复杂度为O(1)。

内容的提问来源于stack exchange,提问作者0jnats3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:03:10