/*
仅用O(1)的空间,将整数数组按奇偶数分成2部分,数组左边是奇数、右边是偶数。
(要求:给出完整代码,尽量高效,简洁)
*/
/*下面是我的写的代码*/
#include <stdio.h>
#define MAX 10
//交换变量
void swap(int *p, int *q)
{
if (p==NULL || q==NULL)
return;
*p ^= *q;
*q ^= *p;
*p ^= *q;
}
//将数组中基数和偶数分离
void arr_deal(int *arr, int num)
{
int i = 0, j = num-1;
if (NULL == arr || num < 1)
return;
while (i < j)
{
while (arr[i]%2==1 && i<j)
i++;
while (arr[j]%2==0 && i<j)
j--;
if (i < j)
swap(&arr[i], &arr[j]);
}
}
//显示数组中的内容
void display(int *arr, int num)
{
int i;
for (i=0; i<num; i++)
printf("%d ", arr[i]);
printf("\n");
}
//主函数
int main(int argc, char *argv[])
{
int arr[MAX] = {2, 22, 4, 5, 3, 6, 3, 27, 0, 11};
display(arr, MAX);
arr_deal(arr, MAX);
display(arr, MAX);
return 0;
}
标准答案:
#include <stdio.h>
#include <stdlib.h>
#define bool int
#define false 0
#define true 1
void Reorder(int *pData, unsigned int length, bool (*func)(int));
bool isEven(int n);
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;
}
}
}
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;
}
}
}
bool isEven(int n)
{
return (n & 1) == 0;
}
对于标准答案的总结:
思路:
两个指针,分别从头和从尾遍历数组
精彩的部分:
定义布尔:有利于代码的可读性
#define false 0
#define true 1
将功能封装成函数:
有利于调试,纠错,提高代码的复用
判断参数的有效性:
有利于代码的健壮性
if(pData == NULL || length == 0)
return;
边界的判断:
while(pBegin < pEnd && (*pBegin & 0x1) != 0)
if(pBegin < pEnd)
{
int temp = *pBegin;
*pBegin = *pEnd;
*pEnd = temp;
}
高效性:
对于除法和乘法,采用位运算,提高效率
pBegin & 0x1
(n & 1) == 0;
利用函数指针,实现切面编程,构成框架:
bool (*func)(int)
调用判断奇数和偶数的判断:bool isEven(int n)(原型)
善用指针:(不知道算不算)
int temp = *pBegin;
*pBegin = *pEnd;
*pEnd = temp;
注释:
在关键的位置标识
不足之处:
将int变装成bool:该设计存在问题
#define bool int
改为typedef int bool
函数参数并没有全部做判定
可能传入非法数值
编程小总结
切面编程:
框架的搭建
现在写好的函数可以调用以后写好的函数
函数参数中有调用的函数,但是不确定,用指针代替,等到想用哪个,就在
外面传入,有利于代码的维护和升级
例如:
要调用bool isEven(int n);
但是没有写出来(计划将来写),但是仍然想先调用其功能(预先想好的功能),函数可以这么写
void Reorder(int *pData, unsigned int length, bool (*func)(int));
调用判断奇数和偶数的判断:bool isEven(int n)(原型)
拓展:
对于不确定,可以都考虑指针,具体要传入参数,在外部指定传入即好
位运算:
遇到乘法、除法、求余,都可以使用位运算,提高效率
例如:
x%2 <=> n&1
注意:只是用在偶数中
例如:
// 向后移动pBegin,直到它指向偶数
while(pBegin < pEnd && (*pBegin & 0x1) != 0) //
pBegin ++;
// 向前移动pEnd,直到它指向奇数
while(pBegin < pEnd && (*pEnd & 0x1) == 0)
pEnd --;
以后要在关键位置注释,比较难懂的代码加上功能注释,需要标识位置(调试)