关于swap函数的使用注意事项

今天动手写了个快速排序:

#include 
typedef int (*data_compare)(int a, int b);

void swap(int *a, int *b)
{
    *a = *a ^ *b;
    *b = *a ^ *b;
    *a = *a ^ *b;
}

int cmp_int(int a, int b)
{
    return a - b;
}

int cmp_int_invert(int a, int b)
{
    return b - a;
}

int partition(int *a, int left, int right, data_compare cmp)
{
    int i;
    int index = left;
    int pivot = a[index];
    swap(&a[index], &a[right]);
    for (i = left; i < right; i++) {
        if (cmp(a[i], pivot) < 0) { 
            swap(&a[index], &a[i]);
            index++;
        }
    }
    swap(&a[index], &a[right]);
    return index;
}

void quick_sort(int *a, int left, int right, data_compare cmp)
{
    int index;
    if (left >= right)
        return;
    index = partition(a, left, right, cmp);
    quick_sort(a, left, index - 1, cmp);
    quick_sort(a, index + 1, right, cmp);
}

int main(void)
{
    int i;
    int a[10] = {3, 8, 5, 4, 9, 7, 1, 6, 2, 0};
    for (i = 0; i < 10; i++)
        printf("%d ", a[i]);
    printf("\n");
    quick_sort(a, 0, 9, cmp_int);
    for (i = 0; i < 10; i++)
        printf("%d ", a[i]);
    printf("\n");
    return 0;
}

运行时发现结果不对:
3 8 5 4 9 7 1 6 2 0
0 1 2 3 0 0 0 0 0 0
怎么数据都变成0了.后面调试了半天,才发现是swap实现有问题.

对于void swap(int *a, int *b),功能很明显,交换指针a和b指向的值。实现的时候有多种方式:

void swap(int *a, int *b)
{
    int tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
}

上述方式是使用一个中间变量,很容易的实现.若使用上述方法,程序可以正常运行

当然我们也可以使用其他方式实现,不使用中间变量,而使用异或的方式,因为两个相同的数异或为零,如下所示:

void swap(int *a, int *b)
{
    *a = *a ^ *b;
    *b = *a ^ *b;
    *a = *a ^ *b;
}

上面的方式咋一看好像没什么问题,但是当a = b时,即交换同一个指针指向的值时,由于*a ^ *b = 0,a指针指向的值为变成0.

因此在partition函数时,left编号的元素与pivot比较时,若条件成立,需要与编号index的元素交换,此时left = index,因此在调用swap时,a[index] = a[left] = 0.

可对上面的swap函数修改下,交换前进行判断,若相同则不用交换,不仅可以消除bug,同时可提高一定的效率:

void swap(int *a, int *b)
{
    if (*a != *b) {
        *a = *a ^ *b;
        *b = *a ^ *b;
        *a = *a ^ *b;
    }
}

修改后程序可正常运行。

你可能感兴趣的:(排序算法)