JavaScript排序算法大解密 - 冒泡、选择、插入、快速排序全解析

发布时间:2024年01月05日

📢?鸿蒙专栏:想学鸿蒙的,冲

📢 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]

冒泡排序是一种简单的排序算法,它的基本思想是通过反复比较和交换相邻元素,使较大的元素逐渐“浮”到数组的末尾,就像气泡一样逐渐上浮。

冒泡排序的详细步骤是:

  1. 从数组开头开始,比较相邻的两个元素,如果顺序是反的(第一个比第二个大),则交换它们的位置。
  2. 对每一对相邻元素都进行同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

可以通过一个示例数组来理解冒泡排序的过程:

原数组:[5, 1, 4, 2, 8]

  1. 第一轮:[1, 5, 4, 2, 8] (5和1交换位置)
  2. 第二轮:[1, 4, 5, 2, 8] (5和4交换位置)
  3. 第三轮:[1, 4, 2, 5, 8] (5和2交换位置)
  4. 第四轮:[1, 4, 2, 5, 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]

选择排序是一种简单直观的排序算法。它的工作原理是:

  1. 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
  2. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
  3. 重复第二步,直到所有元素均排序完毕。

举例:

原数组:[5, 3, 6, 2, 10]

  1. 第一轮:将3与5交换位置,得到[3, 5, 6, 2, 10]
  2. 第二轮:将2与5交换位置,得到[3, 2, 6, 5, 10]
  3. 第三轮:将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]

????????插入排序的工作原理是,将数组分为两个部分,前面部分是有序的,后面部分是无序的。每次从无序部分取出第一个元素,并把它插入到有序部分中的正确位置。

插入排序包含以下步骤:

  1. 从第一个元素开始,该元素可以认为已经被排序。
  2. 取出下一个元素,在已排序的元素序列中从后向前扫描。
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置。
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置。
  5. 将新元素插入到该位置后。
  6. 重复步骤2~5。

例如对数组[5,2,4,6,1,3] 排序:

  1. 第一轮:取出2,插入有序序列[5],变为 [2,5]
  2. 第二轮:取出4,插入有序序列[2,5],变为[2,4,5]
  3. 第三轮:取出6,插入有序序列[2,4,5],变为[2,4,5,6]
  4. 第四轮:取出1,插入有序序列[2,4,5,6],变为[1,2,4,5,6]
  5. 第五轮:取出3,插入有序序列[1,2,4,5,6],变为[1,2,3,4,5,6]

????????可以看出,插入排序逐步构建有序序列,对于少量元素的数组,插入排序能够有效减少交换和移动次数。

????????插入排序的时间复杂度是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)。具体算法步骤如下:

  1. 从数列中挑出一个元素,称为 “基准”(pivot)
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。这个算法一定会结束,因为在每次的迭代(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算法充分利用数据结构,通过巧妙地比较和交换来实现顺序的重组。希望通过本文的讲解,大家可以掌握这些经典算法的精髓所在,并能够灵活运用到实际工作中。排序算法也可以经过改进来获得更好的性能,这需要我们不断地学习和优化。

????????如果本文对你有帮助,请分享给你的朋友!你也可以在评论区留言,与我讨论和交流排序算法的实践经验。最后,感谢你的阅读,希望大家在算法学习的路上能不断进步!

????????我们改日再会

文章来源:https://blog.csdn.net/qq_41152573/article/details/135403943
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。