【思 路1】首先我们不考虑时间复杂度的要求,直观考虑:我们只需要从头到尾扫描整个数组,如果碰到奇数,放到第一的位置;如果碰到偶数,就放到最后的位置。这样就OK了。然后我们来分析这种算法的效率问题:首先我们需要一个临时变量来保存需要移动的元素,因而空间复杂度为O(1).时间上,对于第i个元素,它是奇数和偶数的概率各为1/2,因而它有1/2的概率向前移动(i-1)个位置,有1/2的概率想后移动(n-i)个位置,因而平均下来要移动(n-1)/2的位置,也就是说对于任意一个元素平均要移动(n-1)/2个其他元素,因而所有元素要移动的次数就是n(n-1)/2,所以这种算法的时间复杂度为O(n)。
【思 路2】这道题只是要求奇数排在偶数的前面,因而我们完全没有必要一个元素一个元素的进行分析,我们可以考虑每次分析一对元素,首尾指针?yes!我们在定义两个指针,分别指向数组的第一个元素和最后一个元素,然后进行判断,如果第一个元素为偶数,第二个元素为奇数,那么我们就交换,否则,我们直接移动指针指向下一个(上一个)元素即可。当两个指针相遇的时候就完成遍历了。这样我们的时间复杂度就为O(n)。根据这种思路,我们可以很容易的写出如下的代码:
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 //重排数组使得所有奇数位于数组的前半部分 6 //所有的偶数位于数组的后半部分 7 void ReorderOddEven(int numbers[],int length) 8 { 9 if(numbers == NULL || length <= 0) 10 return; 11 12 //首尾指针,两头往中间遍历 13 int *start = &numbers[0]; 14 int *end = &numbers[length-1]; 15 16 while(start < end) 17 { 18 //首指针指向奇数,指针后移 19 if(*start % 2 == 1) 20 { 21 start++; 22 continue; 23 } 24 25 //尾指针指向偶数,指针前移 26 if(*end % 2 == 0) 27 { 28 end--; 29 continue; 30 } 31 32 //首指针指向指向偶数,同时尾指针指向奇数,交换; 33 int temp = *start; 34 *start = *end; 35 *end = temp; 36 } 37 38 } 39 40 int main() 41 { 42 cout<<"Enter your arrayLength:"<<endl; 43 int n = 0; 44 cin>>n; 45 46 cout<<"Enter your array elements:"<<endl; 47 int *array = new int[n]; 48 for(int i = 0;i < n;++i) 49 { 50 cin>>array[i]; 51 } 52 53 cout<<"the orginal array is:"<<endl; 54 for(i = 0;i < n;++i) 55 { 56 cout<<array[i]<<" "; 57 } 58 cout<<endl; 59 60 ReorderOddEven(array,n); 61 62 cout<<"the resorted array is:"<<endl; 63 for(i = 0;i < n;++i) 64 { 65 cout<<array[i]<<" "; 66 } 67 cout<<endl; 68 69 return 0; 70 }
运行结果如下:
反思:这道题很简单,基本上稍作思考,就能写出如上的代码,然而仍然有很多小细节没有注意到,何海涛博主的考虑得就比较的全面,这个代码的重用性很差,如果换成所有的负数排在所有的正数的前面,我们就要重新修改函数中的部分代码,他在博客中将该函数分离开来,做到了重排数组的算法和重排标准的分离,这样只要修改重排标准,就可以轻易的实现代码的重用。看来我水平还是差很多,继续努力!