剑指Offer-调整数组顺序使奇数位于偶数前面
题目
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
解法探析
解法 1
若在不考虑时间复杂度的情况下,可以从头扫描这个数组,每碰到一个偶数,取出该数字,并把该数字后面的所有数字往前移一位。移完之后在数组的末尾有一个空位,再把该偶数放入到这个空位。由于每碰到一个偶数就要移动 \(O(n)\)个数字,故总的时间复杂度为 \(O(n^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;
}
}
}
解法 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);
}
个人主页: