1、题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
解法:若不考虑时间复杂度,最简单的思路是从头扫描这个数组,每碰到一个偶数时,拿出这个数字,并把位于这个是数字后面的所有数字往前挪动一位。挪完之后在数组的末尾有一个空位,这时把该偶数放入这个空位。由于每碰到一个偶数就需要移动O(n)个数字,因此总的时间复杂度是O(n^2)。
方法:
扫描数组时,如果发现有偶数出现在奇数的前面,交换他们的顺序即可。我们维护两个指针,第一个指针初始化是指向数组的第一个数字,它只向后移动。第二个指针初始化时指向数组的最后一个数字,它只向前移动。在两个指针相遇之前,第一个指针总是位于第二个指针的前面。如果第一个指针指向的数字是偶数,并且第二个指针指向的数字是奇数,就交换这两个数字。
void ReorderOddEven(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;
}
}
}
2、题目扩展:
把题目改成把数组中的数按照大小分为两部分,所有负数都排在非负数的前面,怎么办?
解法:只需修改函数ReorderOddEven中的两处判断的标准即可。把判断的标准变成一个函数指针,也就是用一个单独的函数来判断数字是不是符合标准。这样就把函数分为两部分:一是判断数字应该在数组前半部分还是后半部分的标准,二是拆分数组的操作。
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)
{
while(pBegin < pEnd && !func(*pBegin))
pBegin++;
while(pBegin < pEnd && func(*pEnd))
pEnd--;
if(pBegin < pEnd)
{
int temp = *pBegin;
*pBegin = *pEnd;
*pEnd = temp;
}
}
}
bool isEven(int n)
{
return (n & 1) == 0;
}
函数Reorder根据func的标准把数组pData分成两部分,函数isEven则是一个具体的标准,即判断一个数是不是偶数。
void ReorderOddEven(int *pData, unsigned int length)
{
Reorder(pData, length, isEven);
}