首页 > 代码库 > 一个关于数组存储特定序列问题的思考
一个关于数组存储特定序列问题的思考
原题要求:
已有一个数组有奇偶数,将奇数放在数组的“左边”,偶数在“右边”
要求不允许在额外使用数组空间。
例如:
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退出了,其实还可以继续向前遍历,直到遇见奇数为止,
但是这样就又来一个问题是增加了一层循环,空间成本上也是不小的开销。
希望能给各位带来一点灵感!
一个关于数组存储特定序列问题的思考