剑指Offer :调整数组顺序使奇数位于偶数前面

1.题目

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。

2.解法探析

2.1 解法 1

若在不考虑时间复杂度的情况下,可以从头扫描这个数组,每碰到一个偶数,取出该数字,并把该数字后面的所有数字往前移一位。移完之后在数组的末尾有一个空位,再把该偶数放入到这个空位。由于每碰到一个偶数就要移动 O ( n ) O(n) O(n)个数字,故总的时间复杂度为 O ( n 2 ) O(n^2) O(n2)

2.2 解法 2

该题要求把奇数放到数组的前半部分,偶数放在数组的后半部分,因此所有的奇数应该在偶数的前面。那么,在扫描这个数组时,若发现有偶数在奇数的前面,就交换它们的顺序。采用双指针的解法如下所示:

void ReorderOddEven(int* pData, unsigned int length)
{
    if (pData == NULL || length == 0) {
        return;
    }

    int* pBegin = pData;                // pBegin指针指向数组的第一个数字
    int* pEnd = pData + length -1;      // pEnd指针指向数组的最后一个数字

    while (pBegin < pEnd) {
        // 向后移动pBegin,直到它指向偶数
        // (*pBegin & 0x1) != 0 表示pBegin指向的是奇数
        while (pBegin < pEnd && (*pBegin & 0x1) != 0) {
            pBegin++;
        }

        // 向前移动pEnd,直到它指向奇数
        // (*pEnd & 0x1) == 0 表示pEnd指向的是偶数
        while (pBegin < pEnd && (*pEnd & 0x1) == 0) {
            pEnd--;
        }

        // 若pBegin指针指向的是偶数,pEnd指针指向的是奇数。则交换这两个数字
        if (pBegin < pEnd) {
            int temp = *pBegin;
            *pBegin = *pEnd;
            *pEnd = temp;
        }
    }   
}

2.3 解法 3

编写代码时我们思考的不应该只是解决一个问题的方法,而是解决一系列同类型问题的通用方法,因为优秀的代码应具有良好的可扩展性。可以将 解法 2 中的整个函数解耦成两部分,一部分是判断数字应该在数组前半部分还是后半部分;另一部分是拆分数组的操作。解耦后的代码如下所示:

void Reorder(int* pData, unsigned int length, bool (*func)(int))
{
    if (pData == NULL || length == 0) {
        return;
    }

    int* pBegin = pData;                // pBegin指针指向数组的第一个数字
    int* pEnd = pData + length -1;      // pEnd指针指向数组的最后一个数字

    while (pBegin < pEnd) {
        // 向后移动pBegin,直到它指向偶数
        while (pBegin < pEnd && !func(*pBegin)) {
            pBegin++;
        }

        // 向前移动pEnd,直到它指向奇数
        while (pBegin < pEnd && func(*pEnd)) {
            pEnd--;
        }

        // 若pBegin指针指向偶数,pEnd指针指向奇数,则交换这两个数字
        if (pBegin < pEnd) {
            int temp = *pBegin;
            *pBegin = *pEnd;
            *pEnd = temp;
        }
    }   
}

// 判断一个数是否为偶数
bool isEven(int n)
{
    // 若是偶数,则返回true,否则返回false
    return (n & 0x1) == 0;
}

void ReorderOddEven(int* pData, unsigned int length)
{
    Reorder(pData, length, isEven);
    // Reorder(pData, length, &isEven);
}

若把问题改成将数组中的负数移到非负数的前面,或者把能被 3 整除的数移到不能被 3 整除的数的前面,都只需定义新的函数来确定分组的标准,而函数 Reorder 不需要进行任何改动。将数组中的负数移到非负数的前面的代码如下所示:

// 判断一个数是否为非负数
bool isNonNegative(int n)
{
    // 若是非负数,则返回true,否则返回false
    return ((n >= 0) ? true : false);
}

void ReorderNonNegAndNeg(int* pData, unsigned int length)
{
    Reorder(pData, length, isNonNegative);
    // Reorder(pData, length, &isNonNegative);
}

个人博客:

www.codeapes.cn

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值