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

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

#include <stdio.h>
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;
    }
}

修改后程序可正常运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值