简体   繁体   English

这种冒泡实现是错误的吗?

[英]Is this implementation of bubble sort wrong?

Instead of using the usual do-while loops for sorting, if we use 2 for loops, would that be okay? 如果我们使用2 for循环,而不是使用通常的do-while循环进行排序,那会没关系吗?

let bubbleSort = (arr) => {
    console.log(arr);
    for(let i=0; i<arr.length; i++) {
        for (j=0; j<arr.length; j++) {
            if (arr[j] > arr[j+1]){
                console.log("swapped (i,j)->", arr[j],arr[j+1])   
                let temp = arr[j+1];
                arr[j+1] = arr[j];
                arr[j] = temp;

            }
        }
    }

    return arr

}

This returns the correct sorted array but is it any better than the do-while loop. 这会返回正确的排序数组,但它比do-while循环更好。 Both are O(n^2) time-complexity. 两者都是O(n ^ 2)时间复杂度。

All loop types do , while and for are equivalent. 所有循环类型dowhilefor是等价的。 They're just syntactic sugar for the programmer and ultimately boil down to the same thing at runtime. 它们只是程序员的语法糖,最终在运行时归结为同样的东西。

What you've posted here is a mostly correct implementation of bubble sort, but there are a few points of improvement available: 你在这里发布的是一个大致正确的冒泡排序实现,但有一些改进点:

  • Bug: the code is accessing an out of bounds index in the inner loop: iterate to j < arr.length - 1 instead of j < arr.length because of the arr[j+1] statement. 错误:代码正在访问内部循环中的越界索引:由于arr[j+1]语句,迭代到j < arr.length - 1而不是j < arr.length Most languages will crash or exhibit undefined behavior for an out of bounds array access, but JS just compares the value against undefined and carries on. 对于越界数组访问,大多数语言都会崩溃或表现出未定义的行为,但JS只是将值与undefined进行比较并继续进行。

  • Potential bug: the inner loop creates a global j variable in the inner loop (thanks to Kaiido for pointing this out). 潜在的错误:内部循环在内部循环中创建一个全局j变量(感谢Kaiido指出这一点)。 This variable's value will persist beyond this function and might cause unexpected behavior elsewhere in the program. 此变量的值将持续超出此函数,并可能导致程序中其他位置的意外行为。 Declare variables with let (or const if the variable shouldn't be reassigned) to ensure that they are scoped locally to the block. 使用let声明变量(如果不应该重新赋值变量,则为const )以确保它们在本地作用于块。

  • After the first iteration of the outer loop, the rightmost element in the array is in its final and sorted location (because it's the largest element in the array). 在外部循环的第一次迭代之后,数组中最右边的元素位于其最终和排序位置(因为它是数组中的最大元素)。 After the second iteration of the outer loop, the last two elements of the array are in their final sorted positions. 在外循环的第二次迭代之后,数组的最后两个元素处于它们的最终排序位置。 And so on. 等等。 Therefore, we can shorten the number of iterations of the inner loop as follows: j < arr.length - 1 - i . 因此,我们可以按如下方式缩短内循环的迭代次数: j < arr.length - 1 - i

  • If on any iteration no swaps were performed, we can break--the array is already sorted. 如果在任何迭代中没有执行交换,我们可以破坏 - 数组已经排序。

These optimizations don't improve the time complexity, which is O(n 2 ) as you say, but they're worth thinking about, as similar optimization approaches can help speed up real-world sort routines. 这些优化并没有改善时间复杂度,正如你所说的那样是O(n 2 ),但它们值得思考,因为类似的优化方法可以帮助加速现实世界的排序例程。

A few style points to consider: 需要考虑几个风格点:

  • Use spacing between operators (unless they're in [] s). 使用运算符之间的间距(除非它们在[] s中)。
  • Consider using a destructuring assignment to avoid the temp variable when swapping values. 在交换值时,请考虑使用解构赋值来避免temp变量。 As pointed out in the comments, this has a performance penalty due to the overhead of array object creation per swap, so it should be compiled out in a production build (although bubble sort wouldn't be appropriate in production anyway). 正如评论中所指出的,由于每个交换创建数组对象的开销,这会带来性能损失,因此应该在生产版本中编译(尽管冒泡排序在生产中也不合适)。
  • Be consistent with semicolons and vertical spaces. 与分号和垂直空间一致。

Here's a possible re-write: 这是一个可能的重写:

 const bubbleSort = arr => { for (let i = 0; i < arr.length; i++) { let swapped = false; for (let j = 0; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j+1]) { [arr[j], arr[j+1]] = [arr[j+1], arr[j]]; swapped = true; } } if (!swapped) { break; } } return arr; }; for (let i = 0; i < 10000; i++) { const arr = Array(100).fill().map(e => ~~(Math.random() * 30)); const expected = JSON.stringify(arr.slice().sort((a, b) => a - b)); const actual = JSON.stringify(bubbleSort(arr.slice())); if (actual !== expected) { throw new Error(`test failed: expected ${expected} but got ${actual}`); } } console.log("10000 tests passed"); 

Fun follow-up exercises: 有趣的后续练习:

  • Write it without loops, using recursion. 使用递归编写没有循环的循环。
  • Allow the user to pass a custom comparator function, similar to the builtin Array#sort . 允许用户传递自定义比较器函数,类似于内置的Array#sort This way, you can sort arrays of objects or specify the order of the sort. 这样,您可以对对象数组进行排序或指定排序顺序。
  • Benchmark it against other sort routines using console.time (thanks to Medet for the idea). 使用console.time对其他排序例程进行基准测试(感谢Medet的想法)。 How much do the optimizations help? 优化有多大帮助? Look into using seeded random numbers for your tests. 考虑使用种子随机数进行测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM