前两天手写快速排序,最后得到的结果是错误的而且还错的非常奇怪。输入的待排序数组是:
int a[10] = {2,6,4,8,0,1,5,9,3,7};
最后得到的结果是:
0 0 2 0 0 0 6 0 8 0
上网看了看别人的代码,发现我写的快速排序的算法逻辑是没有错误的,难道是交换元素时用的算法不对?
我用的交换算法是异或交换,就是不用中间变量那种:
void swap( int *a, int *b ) { *a = *a + *b; *b = *a - *b; *a = *a - *b; }
然后将其换成使用中间变量的交换算法:
void swap( int *a, int *b ) { int temp; temp = *a; *a = *b; *b = temp; }
然后结果就对了,但是一直想不明白为什么。最后通过在纸上演算一遍才恍然大悟。
例如我这个输入:
2 6 4 8 0 1 5 9 3 7
中间的比较交换过程略去不表,然后它会到达这么一个状态:
0 /1 / 2 / 8 4 6 5 9 3 7
^
^
解释一下,第一轮排序将2放到属于它的位置,然后分成左边的序列0 1和右边的序列8 4 6 5 9 3 7。第二轮对左边的0 1进行排序,将0放置到属于它的位置(没动)。第三轮对1进行排序,问题就出在这里,由于只有一个元素,但按照算法也要进行一次交换,如果使用不借助中间变量的交换算法(加减法、异或法),传递给void swap( int *a, int *b )的a, b指向的是同一地址,也就是说实际上是这样的:
void swap( int *a, int *a ) { *a = *a + *a; *a = *a - *a; //*a==0,永世不得翻身 *a = *a - *a; }
其实在第二轮时,0与0交换就出现了这个问题,但是由于它是0没有表现出来。
以前总觉得不用中间变量的交换算法稍微有那么点帅,看来还是得想好了再用。可靠性最重要啊。
原文:http://www.cnblogs.com/leauky/p/7820251.html