原题要求:
已有一个数组有奇偶数,将奇数放在数组的“左边”,偶数在“右边”
要求不允许在额外使用数组空间。
例如:
Before sort:
1 2 3 4 5 6 7 8 9 10
After sort:
1 9 3 7 5 6 4 8 2 10
初看之下立马有了一个思路:奇偶对调。即使用遍历的方式首尾各自遍历,首部发现偶数后与尾部发现的奇数进行交换位置。
1 #include <stdio.h>
2
3 #define N 10
4
5 int count=0;
6
7 void arrsort(int *a,int len){
8 int i,j;
9 for(i=0;i<len;i++){
10 for(j=len-1;j>i;j--){
11 count++; // 用于计数,统计循环次数
12 if(!(a[i] & 0x01)){
13 if(a[j] & 0x01){
14 a[i] ^= a[j];
15 a[j] ^= a[i];
16 a[i] ^= a[j];
17 break;
18 }
19 } else break;
20 }
21 }
22 }
23
24 int main(){
25 int k;
26 int a[N]={1,2,3,4,5,6,7,8,9,10};
27 printf("Before sort:\n");
28 for(k=0;k<N;k++){
29 printf("%d ",a[k]);
30 }
31 arrsort(a,N);
32 printf("\nAfter sort:\n");
33 for(k=0;k<N;k++){
34 printf("%d ",a[k]);
35 }
36 printf("\nTotal count is: %d\n",count);
37 return 0;
38 }
输出结果:
Before sort:
1 2 3 4 5 6 7 8 9 10
After sort:
1 9 3 7 5 6 4 8 2 10
Total count is: 19 -- 内循环执行了19次
看执行的结果是正确了,但是从主观的角度来说,这个循环次数有点多啊,直观上看,其实就是交换3组数(2-9、3-8、4-7),需要用到19次?
还是优化一下吧
思路:若是首部的数是奇数,则自动跳转到下一顺位继续判断,所以内层循环可以不用执行,因此将
if(!(a[i] & 0x01)){ // 判断为偶数
语句调整至外层循环内,即:
5 void arrsort(int *a,int len){
6 int i,j;
7 for(i=0;i<len;i++){
8 <span style="color:#FF0000;"><strong>if(a[i] & 0x01) continue;</strong></span>//非偶数时直接跳过
9 for(j=len-1;j>i;j--){
10 count++;
11 if(a[j] & 0x01){
12 a[i] ^= a[j];
13 a[j] ^= a[i];
14 a[i] ^= a[j];
15 break;
16 }
17 }
18 }
19 }
输出结果:
Before sort:
1 2 3 4 5 6 7 8 9 10
After sort:
1 9 3 7 5 6 4 8 2 10
Total count is: 16 -- 内循环执行了16次
恩,总算是一个进步不是,虽然这个进步有点小!
还可以再短吗?这个好像。。。似乎。。。应该。。。可以吧?!
我们忽略了一个常见的思考手段,当首部和尾部进行一次交换后,随后的遍历应该可以把各自对应的位置“忽略”
即比如交换了第1位和第9位,那么在下一次遍历时候首部应从第2位、而尾部应该从第8位开始(首部是正序,尾部是倒序)
所以以上两种方式都忽略了尾部的倒序开始位置,所以做了很多无用的遍历。
按照这个思路调整一下,得到:
5 void arrsort(int *a,int len){
6 int i,j,n;
7 n=len;
8 for(i=0; i<n; i++){
9 if(a[i] & 0x01) continue;
10 for(j=n-1; j>i; j--){
11 count++;
12 if(a[j] & 0x01){
13 a[i] ^= a[j];
14 a[j] ^= a[i];
15 a[i] ^= a[j];
n=j;
16 break;
17 }
18 n=j;
19 }
20 }
21 }
输出结果:
Before sort:
1 2 3 4 5 6 7 8 9 10
After sort:
1 9 3 7 5 6 4 8 2 10
Total count is: 4 -- 循环执行了4次
哇卡卡,这个进步应该不算小了吧!
还能再优化吗?这个问题留个我们大家一起吧。
突然想到一个思路:
内层循环中交换一次后采用了break退出了,其实还可以继续向前遍历,直到遇见奇数为止,
但是这样就又来一个问题是增加了一层循环,空间成本上也是不小的开销。
希望能给各位带来一点灵感!