2021-06-15 记录一次由位运算实现swap产生的bug

今天使用别人的案例来理解三路快速排序,看了许多的案例,也尝试copy过来运行,但始终会出现“0”这种原始数组中不存在的数,我仔细看过,代码本身并没有什么问题,因为大家写的都是几乎一样的,唯一的问题最后发现竟然出现在swap上!
换成用临时变量实现的swap之后,就不存在这个问题了。

    private static void swap(int[] a, int i, int j) {
        a[i] = a[i] ^ a[j];
        a[j] = a[i] ^ a[j];
        a[i] = a[i] ^ a[j];
    }

这个方式是通过位运算来交换数值的,不使用临时变量,看起来很高大上,所以我就使用了。
但是,在这种情况下,它会出现数据变成“0”问题,不知道是什么原因造成的。
可能是这个交换方式不适用于递归吧。

import java.util.Arrays;
import java.util.Random;

public class MySort {

    public static void main(String[] args) {
        Random random = new Random();
        int arrLen = 20;
        int[] arr = new int[arrLen];
        for (int i = 0; i < arrLen; i++) {
            arr[i] = random.nextInt(400);
        }
        int[] array = new int[]{112, 155, 147, 111, 335, 31, 259, 24, 351, 375, 321, 333, 146, 167, 367, 384, 252, 184, 268, 48, 390, 132, 299, 364, 351, 149, 271, 18, 301, 85};
        System.out.printf("待排序的原始数组:%s\n", Arrays.toString(array));
        quickSort3(array);
        System.out.printf("排序完成后的数组:%s\n", Arrays.toString(array));
    }

    //交换
    private static void swap(int[] a, int i, int j) {
        a[i] = a[i] ^ a[j];
        a[j] = a[i] ^ a[j];
        a[i] = a[i] ^ a[j];
    }
    // private static void swap(int[] a, int i, int j) {
    //     int temp = a[i];
    //     a[i] = a[j];
    //     a[j] = temp;
    // }
    
    private static void quickSort3(int[] a) {
        quickSort3(a, 0, a.length - 1);
    }

    private static void quickSort3(int[] a, int left, int right) {
        if (right <= left)
            return;
        /*
         * 工作指针
         * p指向序列左边等于pivot元素的位置
         * q指向序列右边等于Pivot元素的位置
         * i指向从左向右扫面时的元素
         * j指向从右向左扫描时的元素
         */
        int p, q, i, j;
        int pivot;// 锚点
        i = p = left;
        j = q = right - 1;
        /*
         * 每次总是取序列最右边的元素为锚点
         */
        pivot = a[right];
        while (true) {
            /*
             * 工作指针i从右向左不断扫描,找小于或者等于锚点元素的元素
             */
            while (i < right && a[i] <= pivot) {
                /*
                 * 找到与锚点元素相等的元素将其交换到p所指示的位置
                 */
                if (a[i] == pivot) {
                    swap(a, i, p);
                    p++;
                }
                i++;
            }
            /*
             * 工作指针j从左向右不断扫描,找大于或者等于锚点元素的元素
             */
            while (left <= j && a[j] >= pivot) {
                /*
                 * 找到与锚点元素相等的元素将其交换到q所指示的位置
                 */
                if (a[j] == pivot) {
                    swap(a, j, q);
                    q--;
                }
                j--;
            }
            /*
             * 如果两个工作指针i j相遇则一趟遍历结束
             */
            if (i >= j)
                break;

            /*
             * 将左边大于pivot的元素与右边小于pivot元素进行交换
             */
            swap(a, i, j);
            i++;
            j--;
        }
        /*
         * 因为工作指针i指向的是当前需要处理元素的下一个元素
         * 故而需要退回到当前元素的实际位置,然后将等于pivot元素交换到序列中间
         */
        i--;
        p--;
        while (p >= left) {
            swap(a, i, p);
            i--;
            p--;
        }
        /*
         * 因为工作指针j指向的是当前需要处理元素的上一个元素
         * 故而需要退回到当前元素的实际位置,然后将等于pivot元素交换到序列中间
         */
        j++;
        q++;
        while (q <= right) {
            swap(a, j, q);
            j++;
            q++;
        }

        /*
         * 递归遍历左右子序列
         */
        quickSort3(a, left, i);
        quickSort3(a, j, right);
    }


}


位运算实现swap产生的结果

待排序的原始数组:[112, 155, 147, 111, 335, 31, 259, 24, 351, 375, 321, 333, 146, 167, 367, 384, 252, 184, 268, 48, 390, 132, 299, 364, 351, 149, 271, 18, 301, 85]
排序完成后的数组:[18, 0, 31, 48, 85, 111, 0, 132, 146, 147, 149, 155, 167, 184, 252, 259, 268, 271, 299, 301, 321, 0, 335, 351, 351, 364, 0, 375, 384, 0]

临时变量实现swap的结果

待排序的原始数组:[112, 155, 147, 111, 335, 31, 259, 24, 351, 375, 321, 333, 146, 167, 367, 384, 252, 184, 268, 48, 390, 132, 299, 364, 351, 149, 271, 18, 301, 85]
排序完成后的数组:[18, 24, 31, 48, 85, 111, 112, 132, 146, 147, 149, 155, 167, 184, 252, 259, 268, 271, 299, 301, 321, 333, 335, 351, 351, 364, 367, 375, 384, 390]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值