剑指Offer:面试题14 调整数组顺序使奇数位于偶数掐面

/*
调整数组顺序使奇数(odd)位于偶数(even)前面:
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于
数组的后半部分


分析:
如果不考虑交换后的所有奇数的顺序或所有偶数的顺序,从后向前与从前向后交换调整(类似于快排的方法)
前面是偶数,后面是奇数就交换




考虑扩展性的解法:
把题目改成数组中的数按照大小分成两部分,所有负数都在非负数的前面,该怎么做?
修改判定条件。
如果改成能被3整除的放在不能被3整除的前面,怎么办?


面试官期待我们提供解决一系列同类型问题的方法。


题目描述:
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,
所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
输入:
每个输入文件包含一组测试案例。
对于每个测试案例,第一行输入一个n,代表该数组中数字的个数。
接下来的一行输入n个整数。代表数组中的n个数。
输出:
对应每个测试案例,
输入一行n个数字,代表调整后的数组。注意,数字和数字之间用一个空格隔开,最后一个数字后面没有空格。
样例输入:
5
1 2 3 4 5
样例输出:
1 3 5 2 4


*/


/*
关键
1 可扩展性版本:
void reorder(int* pArr,int iLen,bool (*pFun)(int n))//针对可扩展性的版本,注意:函数指针格式:返回值(*指针名)(形参列表)
bool isEven(int n)//判断是否是偶数
{
return (n & 0x1) == 0;
}


2 if(pFront < pBack)//注意,这里一定要加这个判断
{
int iTemp = *pFront;
*pFront = *pBack;
*pBack = iTemp;
}
3 if(!pFun(pArr[i]) && pFun(pArr[i-1]))//如果当前数是奇数,并且其前面的数是偶数
{
int iTemp = pArr[i];
for(int k = i - 1 ; k >= i - iEvenNum; k--)//易错,将恰面的n个偶数向后挪动,应该从后向前
{
pArr[k+1] = pArr[k];
}
*/


#include <stdio.h>
const int MAXSIZE = 10000;




//应该先从前向后,在确保当前数是奇数,且前面N个数是偶数的情况下,把前面n个偶数依次后移,然后将最后的奇数调至第一个偶数处
//1 3 2 4 5 
void reorder_keepSeq(int* pArr,int iLen,bool (*pFun)(int n))//保持奇数与奇数,偶数与偶数之间的相对顺序不变,只能采用碰到一个
{
int iEvenNum = 0;
for(int i = 0 ; i < iLen ; i++)
{
if(pFun(pArr[i]))//统计偶数的个数
{
iEvenNum++;
}
if(i)//如果i不为0,开始统计
{
if(!pFun(pArr[i]) && pFun(pArr[i-1]))//如果当前数是奇数,并且其前面的数是偶数
{
int iTemp = pArr[i];
for(int k = i - 1 ; k >= i - iEvenNum; k--)//易错,将恰面的n个偶数向后挪动,应该从后向前
{
pArr[k+1] = pArr[k];
}
pArr[i-iEvenNum] = iTemp;//将奇数调整到前面
}
}
}
}


void reorder(int* pArr,int iLen,bool (*pFun)(int n))//针对可扩展性的版本,注意:函数指针格式:返回值(*指针名)(形参列表)
{
if(pArr == NULL || iLen <= 0)
{
return;
}
int* pFront = pArr;
int* pBack = pArr + iLen - 1;
while(pFront < pBack)
{
while(pFront < pBack && pFun(*pBack))//从后向前如果是偶数,指向向前移动
{
pBack--;
}
while(pFront < pBack && !pFun(*pFront))//从前向后,如果是奇数,向后移动
{
pFront++;
}
if(pFront < pBack)//注意,这里一定要加这个判断
{
int iTemp = *pFront;
*pFront = *pBack;
*pBack = iTemp;
}
}
}


bool isEven(int n)//判断是否是偶数
{
return (n & 0x1) == 0;
}


bool isNegative(int n)
{
return n < 0;
}


bool isTripe(int n)//tripe:三倍
{
return n % 3 == 0;
}




void print(int* pArr,int iLen)
{
for(int i = 0 ; i < iLen ; i++)
{
if(i)
{
printf(" %d",pArr[i]);
}
else
{
printf("%d",pArr[i]);
}
}
printf("\n");
}


void process()
{
int iArr[MAXSIZE];
int n;
while(EOF != scanf("%d",&n))
{
for(int i = 0 ; i < n ; i++)
{
scanf("%d",&iArr[i]);
}
//reorder(iArr,n,isEven);
reorder_keepSeq(iArr,n,isEven);
print(iArr,n);
}
}


int main(int argc,char* argv[])
{
process();
getchar();
return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值