前端踩坑指南:慎重使用ES6三数互换语法糖

239 阅读1分钟

起因

今天在写非递归快速排序的时候,有一个地方需要使用三数互换,于是用了ES6数组解构的方式进行互换,代码如下:

function quickSort(nums) {
  let left = 0,
    right = nums.length - 1;
  let st = [[left, right]];
  while (st.length != 0) {
    let now = st.pop();
    if (now[0] >= now[1]) continue;
    let i = now[0],
      j = now[1],
      flag = now[0];
    while (i < j) {
      while (j > flag && nums[j] >= nums[flag]) j--;
      if (j <= i) break;
      while (i < j && nums[i] <= nums[flag]) i++;
    [nums[flag], nums[i], nums[j]] = [nums[j], nums[flag], nums[i]]; // 三数互换
      flag = i;
    }
    st.push([now[0], flag - 1]);
    st.push([flag + 1, now[1]]);
  }
}

let nums = [5, 4, 7, 11, 0, 3, 8, 9];
quickSort(nums);
console.log(nums);

输出结果为:

[
  0, 3, 4, 5,
  7, 7, 8, 9
]

将三数互换语句换为[nums[flag], nums[j], nums[i]] = [nums[j], nums[i], nums[flag]],答案就正确了。

这。。。不合理啊😭

分析

于是乎,单点运行,开始debug......

发现盲点,因为有一次交换时,i和j的值是相同的,出现了下面的错误。

let list = [11, 7, 8, 9];

// [list[0], list[3], list[3]] = [list[3], list[0], list[3]]; // 错误,list[3]的值被旧的值覆盖了
[list[0], list[3], list[3]] = [list[3], list[3], list[0]]; // 正确

console.log(list)

结论

所以,三数互换尽量少用,除非你能保证这三个数的下标不同,否则可能出现意想不到的错位。

还是用最古典的三数互换吧😏,不容易出错。

function quickSort(nums) {
  let left = 0,
    right = nums.length - 1;
  let st = [[left, right]];
  while (st.length != 0) {
    let now = st.pop();
    if (now[0] >= now[1]) continue;
    let i = now[0],
      j = now[1],
      flag = now[0];
    while (i < j) {
      while (j > flag && nums[j] >= nums[flag]) j--;
      if (j <= i) break;
      while (i < j && nums[i] <= nums[flag]) i++;
    // [nums[flag], nums[j], nums[i]] = [nums[j], nums[i], nums[flag]]; // 正确,但是慎重使用
    // [nums[flag], nums[i], nums[j]] = [nums[j], nums[flag], nums[i]]; // 错误
    let temp = nums[flag];
    nums[flag] = nums[j],nums[j] = nums[i], nums[i] = temp; // 不易出错
      flag = i;
    }
    st.push([now[0], flag - 1]);
    st.push([flag + 1, now[1]]);
  }
}

let nums = [5, 4, 7, 11, 0, 3, 8, 9];
quickSort(nums);
console.log(nums);