【Yaoze的Bug记录】 01 指针实现的异或算法 xor 的潜在bug——同一个地址自我异或 产生0

Bug记录-01


教材: 十二五规划教材 数据结构 (第2版) 陈越主编

问题描述

今天在写学校的快速排序,闲的没事打算用异或交换算法(指针实现)指针实现快速排序,发现自己的排序序列莫名其妙会有一些元素变成0

在这里插入图片描述

异或交换算法(指针实现)

看起来人畜无害的样子

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

指针版的快速排序算法


void Qsort_p(int arr[], int *left, int *right, const int len)
{
    const int cutoff = 3;
    if (cutoff <= right - left) // 调用快排
    {
        Median(arr, left, right);           // 按照中值标准选取主元,并将主元置于倒数第2个位置
        int *pivot = right - 1;             // 主元
        int *low = left, *high = right - 1; // 左端起始和右端起始       
        while (1)                           // 因为 arr[i]   相当于*(arr+i)      因此直接操作指针在快排时会比使用变址运算符[]更快,每次都减少一次加法运算
        {
            /*
            while (*low < *pivot)
                low++; 
            while (*high > *pivot)
                high--; 
                */  //这样写运气好的话可能会进死循环    当*pivot=*high=*low
                // test_200_d.txt的数据
                // 显然*++low  和*low++ 这2种写法也行不通)
            while(*++low<*pivot);
            while(*--high>*pivot) ;
            if (low < high)
                xor_swap(low, high); // 交换2个数
            else
                break;
        }
        xor_swap(low, pivot);

        if (!bench_test)
            print_arr(arr, len); // 非基准测试下打印过程

        Qsort_p(arr, left, low - 1, len);  // 递归解决左边
        Qsort_p(arr, low + 1, right, len); // 递归解决右边
    }
    else
    {
        insertion_sort(left, right - left + 1); // 规模过小调用插入排序
    }
    return;
}

中值基准选取

void Median(int arr[],int *left,int *right)
{
    const int middle=(left-arr+right-arr)/2;
    if(*left>arr[middle])  xor_swap(left,&arr[middle]);
    if(*left>*right)   xor_swap(left,right);
    if(arr[middle]>*right)  xor_swap(&arr[middle],right);
    

    xor_swap(&arr[middle],right-1);     //发现问题的位置
    return ;
}

原因分析:

根本原因是对同一个地址进行了自我异或,导致该地址上的数字变成了0

一开始并没有往xor_swap上想,毕竟这个程序里还跑了冒泡和堆排序,都使用了xor_swap进行异或交换,但都没有发生问题。

定位问题

在这里插入图片描述

可以看出在进入xor_swap前 arr中还没有0出现,并且快排算法仍在正常运行。
但是进入xor_swap并完成第一次异或操作后发现两个操作数都变成了0;

这时候看了一眼两个操作数的地址,于是恍然大悟
在这里插入图片描述
xor交换的基本原理就是利用两个数的存储位置不同,一个数的部分二进制位可能会暂时为0,直到异或后再恢复/交换。
但是如果两个数的存储位置完全一致,暂时的为0 就变成了永久的,后面怎么异或都回不来了。毕竟0^0=0


解决方案:

加个条件判断即可,地址相同的数本身就不需要交换

void xor_swap(int *a,int *b)
{
    if(a!=b)    //地址相同不需要交换 ,同一个地址自我异或会产生0
    {
    *a^=*b;
    *b^=*a;
    *a^=*b;
    }
    return;
}

指针版快速排序正常运行

在这里插入图片描述
下一步就剩内存泄漏检查和基准测试就可以交报告了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值