起因
今天在写非递归快速排序的时候,有一个地方需要使用三数互换,于是用了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);