交换算法引起的快速排序错误

前两天手写快速排序,最后得到的结果是错误的而且还错的非常奇怪。输入的待排序数组是:

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没有表现出来。

 

以前总觉得不用中间变量的交换算法稍微有那么点帅,看来还是得想好了再用。可靠性最重要啊。

posted @ 2017-11-11 22:39  leauky  阅读(274)  评论(0编辑  收藏  举报