剑指Offer学习总结-调整数组顺序使奇数位于偶数前面

剑指Offer学习总结-调整数组顺序使奇数位于偶数前面

本系列为剑指Offer学习总结,主要是代码案例的分析和实现:
书籍链接:http://product.dangdang.com/24242724.html
原作者博客:http://zhedahht.blog.163.com/blog/static/254111742011101624433132/
原作者博客链接有完整的项目代码下载。


调整数组顺序使奇数位于偶数前面

题目

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

第一眼看到的解法:

如果不考虑时间复杂度, 最简单的思路应该是从头扫描这个数组, 每碰到一个偶数时, 拿出这个数字,
并把位于这个数字后面的所有数字往前挪动一位。挪动之后,我们数组末尾可以空出一个位置,把该偶数放入这个空位 ,
由于每次碰到一个偶数都需要挪动n次, 因此总的时间复杂度是O(n2).

完成基本功能的解法

这个题目要求把奇数放在数组的前半郁分, 偶数放在数组的后半部分, 因此所有的奇数应该位于偶数的前面。
也就是说我们在扫描这个数组的时候, 如果发现有偶数出现在奇数的前面, 我们可以交换它们的顺序,
交换之后就符合要求了。
因此我们可以维护两个指针, 第一个指针初始化时指向数组的第1个数字, 它只向后移动;
第二个指针初始化时指向数组的最后1个数字, 只向前移动。
在两个指针相遇之前, 第一个指针总是位于第二个指针的前面。 如果第一个指针指向的数字是偶数,
并且第二个指针指向的数字是奇数, 我们就交换这两个数字。
这里写图片描述
问题分析到这里,思路就很明确了,我们可以写出下列的代码。

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

    int *pBegin = pData;
    int *pEnd = pData + length - 1;

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

        // 向前移动pEnd,直到它指向奇数
        while(pBegin < pEnd && (*pEnd & 0x1) == 0)
            pEnd --;

        if(pBegin < pEnd)
        {
            int temp = *pBegin;
            *pBegin = *pEnd;
            *pEnd = temp;
        }
    }
}

可扩展的解法

前边的思路代码,已经可以解决我们现有的问题,但是如果题目要求发生了改动呢?

如果把题目改成把数组中的数按照大小分为两部分, 所有负数都在非负数的前面, 该怎么做?
如果再把题目改改, 变成把数组中的数分为两部分, 能被 3整除的数都在不能被 3 整除的数的前面,怎么办?

我们可以发现,改动类似的需求,我们程序的整体流程不需要改动,只需要改动判断的部分(上边的题目是判断是否是奇数偶数)
这里我们使用函数指针来进行扩展功能。函数指针,类似于C#中的委托功能。

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

    int *pBegin = pData;
    int *pEnd = pData + length - 1;

    while(pBegin < pEnd) 
    {
        // 向后移动pBegin
        while(pBegin < pEnd && !func(*pBegin))
            pBegin ++;

        // 向前移动pEnd
        while(pBegin < pEnd && func(*pEnd))
            pEnd --;

        if(pBegin < pEnd)
        {
            int temp = *pBegin;
            *pBegin = *pEnd;
            *pEnd = temp;
        }
    }
}

void ReorderOddEven_2(int *pData, unsigned int length)
{
    Reorder(pData, length, isEven);
}
//具体不同条件的判断 只需要更改这里即可 或者重新添加新的isEven函数实现,改变Reorde传入的参数。
bool isEven(int n)
{
    return (n & 1) == 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值