鸿蒙专栏:想学鸿蒙的,冲
C语言专栏:想学C语言的,冲
VUE专栏:想学VUE的,冲这里
CSS专栏:想学CSS的,冲这里
Krpano专栏:想学VUE的,冲这里
上述专栏,都在不定期持续更新中!!!!
目录
✨ 前言
冒泡排序
选择排序
插入排序
快速排序
✨ 结语
排序是计算机科学中一个经典的问题。良好的排序算法可以大大提高程序的性能。本文将全面解析几种JavaScript中的经典排序算法实现,包括冒泡排序、选择排序、插入排序和快速排序。通过示例代码和逻辑说明,你将学会这些排序算法的基本思路,时间和空间复杂度,以及如何在JavaScript中实现。排序算法的精妙之处在于充分利用数据结构,通过巧妙的交换与比较来完成排序,值得每一位计算机从业者细细品读。本文将由浅入深,从排序原理说明到具体代码实现,帮你深入掌握这些精巧的算法。相信通过学习本文,你将可以熟练掌握各类排序算法的JS实现,在未来的编程工作中运用自如,对于提升你的数据结构与算法能力大有裨益。那么,让我们开始JavaScript排序算法的奥秘之旅吧!
function bubbleSort(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j+1]) {
let temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
return arr;
}
let arr = [5, 2, 4, 6, 1, 3];
console.log(bubbleSort(arr)); // [1, 2, 3, 4, 5, 6]
冒泡排序是一种简单的排序算法,它的基本思想是通过反复比较和交换相邻元素,使较大的元素逐渐“浮”到数组的末尾,就像气泡一样逐渐上浮。
冒泡排序的详细步骤是:
- 从数组开头开始,比较相邻的两个元素,如果顺序是反的(第一个比第二个大),则交换它们的位置。
- 对每一对相邻元素都进行同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
可以通过一个示例数组来理解冒泡排序的过程:
原数组:[5, 1, 4, 2, 8]
从上面的过程可以看出,冒泡排序通过交换相邻不符合顺序的元素位置,让较大的元素向上逐步“浮动”,每一轮下来最大的元素都会被交换到最后的位置,直到数组完全有序。
冒泡排序的时间复杂度在最坏情况下是O(n^2),因为有两个嵌套的循环。空间复杂度为O(1),只需要一个临时变量用于交换。冒泡排序的主要优点是算法简单,但是它的效率较低,通常只适用于小规模的排序。对于大数据量,会有更优的算法选择,如快速排序等。
function selectionSort(arr) {
for (let i = 0; i < arr.length; i++) {
let minIndex = i;
for (let j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
let temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
let arr = [5, 3, 6, 2, 10];
console.log(selectionSort(arr)); // [2, 3, 5, 6, 10]
选择排序是一种简单直观的排序算法。它的工作原理是:
举例:
原数组:[5, 3, 6, 2, 10]
- 第一轮:将3与5交换位置,得到[3, 5, 6, 2, 10]
- 第二轮:将2与5交换位置,得到[3, 2, 6, 5, 10]
- 第三轮:将2与6交换位置,得到[2, 3, 6, 5, 10]
可以看出,选择排序通过找到未排序的最小值,放到已排序序列的末尾,经过n-1轮后得到有序序列。
选择排序时间复杂度为O(n^2),因为需要两层循环来选择最小值。空间复杂度为O(1)。
选择排序由于简单, Performance也比冒泡排序好,但仍是O(n^2)的复杂度。它适合对小规模数组排序。对于大数据量,也有更优的排序算法选择。
选择排序的主要优点是比较次数少,对于大规模数组,交换所需时间少,然而步骤单一,各轮排序并无交叉进行,速度较慢。可以适当优化算法提高速度。
function insertionSort(arr) {
for (let i = 1; i < arr.length; i++) {
let curr = arr[i];
let j = i - 1;
while (j >= 0 && curr < arr[j]) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = curr;
}
return arr;
}
let arr = [5, 2, 4, 6, 1, 3];
console.log(insertionSort(arr)); // [1, 2, 3, 4, 5, 6]
插入排序的工作原理是,将数组分为两个部分,前面部分是有序的,后面部分是无序的。每次从无序部分取出第一个元素,并把它插入到有序部分中的正确位置。
插入排序包含以下步骤:
- 从第一个元素开始,该元素可以认为已经被排序。
- 取出下一个元素,在已排序的元素序列中从后向前扫描。
- 如果该元素(已排序)大于新元素,将该元素移到下一位置。
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置。
- 将新元素插入到该位置后。
- 重复步骤2~5。
例如对数组[5,2,4,6,1,3] 排序:
可以看出,插入排序逐步构建有序序列,对于少量元素的数组,插入排序能够有效减少交换和移动次数。
插入排序的时间复杂度是O(n^2),空间复杂度为O(1)。相比冒泡排序和选择排序,插入排序能够更快地对部分有序数组进行排序。因此适合对小规模数组排序。
function quickSort(arr, left = 0, right = arr.length - 1) {
if (left < right) {
let pivotIndex = partition(arr, left, right);
quickSort(arr, left, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, right);
}
return arr;
}
function partition(arr, left, right) {
let pivot = arr[Math.floor((left + right) / 2)];
while (left <= right) {
while (arr[left] < pivot) {
left++;
}
while (arr[right] > pivot) {
right--;
}
if (left <= right) {
[arr[left], arr[right]] = [arr[right], arr[left]];
left++;
right--;
}
}
return left;
}
let arr = [5, 2, 4, 6, 1, 3];
quickSort(arr);
console.log(arr); // [1, 2, 3, 4, 5, 6]
快速排序使用分治策略来把一个串行(list)分为两个子串行(sub-lists)。具体算法步骤如下:
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。这个算法一定会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
例如序列:[5, 3, 8, 4, 1, 7, 2, 6]
选择5为基准,第一次分区后变为:[3, 2, 1, 4, 5, 7, 8, 6],5处于中间位置
接着递归排序左右两个子序列。
快速排序利用了分治策略,能够快速排序,时间复杂度为O(nlogn),是非常高效的排序算法。但空间复杂度较高,为O(nlogn),需要额外空间recursion调用。
快速排序是原地排序,不需要额外空间,并且时间效率很高,适合排序大数据量。是最常用的排序算法之一。
总结来说,排序算法是计算机科学中一个非常基础和经典的问题。本文详细介绍和分析了几种JavaScript中的排序算法实现,包括冒泡排序、选择排序、插入排序和快速排序,通过示例代码阐明了各类排序的原理和步骤。
不同的排序算法根据其时空复杂度的不同,都有其应用场景。一般来说,简单排序如冒泡排序和选择排序时间复杂度较高,仅适用于小规模数组;而插入排序和快速排序更适合对大数据量的数组进行排序。
sorting算法充分利用数据结构,通过巧妙地比较和交换来实现顺序的重组。希望通过本文的讲解,大家可以掌握这些经典算法的精髓所在,并能够灵活运用到实际工作中。排序算法也可以经过改进来获得更好的性能,这需要我们不断地学习和优化。
如果本文对你有帮助,请分享给你的朋友!你也可以在评论区留言,与我讨论和交流排序算法的实践经验。最后,感谢你的阅读,希望大家在算法学习的路上能不断进步!
我们改日再会