前言
排序算法是数据结构和算法之中的基本功,虽说做前端开发不经常用到算法,但在求职或跳槽时的笔试和面试题目中出现频率还是非常高的。所以掌握一些基本的算法,对于技术人员无疑是非常重要的。
这里只介绍四种JS排序算法:冒泡排序、选择排序、插入排序、快速排序。后面看了其他算法的话,再补充。
算法思想的描述是通过我自己的理解之后,说得比较通俗一点,没理解的可以自行百度(谷歌)这些算法。
冒泡排序
冒泡排序是排序算法中最简单的一个算法,因为简单,所以比较好理解和容易实现,适用于性能要求不高和数据量不大的场景。
算法思想:依次比较相邻两个元素,若第一个比第二个大,则交换位置,否则不交换。这样一轮比较过后,最大的数会排在最后一位。然后再对剩下的 n-1 个元素重复此过程。
代码实现如下:
function bubbleSort(arr) {
for(let i = 0, len = arr.length; i < len; i++) {
for(let j = 0; j < len - 1; j++) {
if(arr[j] > arr[j+1]) {
let temp = arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp
}
}
}
return arr
}
冒泡排序的时平均间复杂度为O(n²),最优时间复杂度为O(n)。
最优时间复杂度的情况是原来的数组本身就是有序数组,可以加一个swapTimes变量,记录相邻两个元素的交换次数。若第一轮两两比较下来,都没有交换过元素位置,证明该数组本身就是有序数组。
最优时间复杂度的代码实现:
function bubbleSort(arr) {
for(let i = 0, len = arr.length; i < len; i++) {
let swapTimes = 0
for(let j = 0; j < len - 1; j++) {
if(arr[j] > arr[j+1]) {
swapTimes++
let temp = arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp
}
}
if(swapTimes < 1) {
break
}
}
return arr
}
选择排序
算法思想:每趟循环找出最大的元素,将其置于数组末尾位置。第一趟找出最大的元素,放置在数组n-1的位置,第二趟放置在n-2的位置,以此类推,直到所有元素都排序完毕。
代码实现:
function selectionSort(arr) {
let len = arr.length
let maxIndex = 0
for(let i = len - 1; i >= 0; i--) {
maxIndex = i
for(let j = 0; j < i; j++) {
if(arr[j] > arr[maxIndex]) {
maxIndex = j
}
}
let temp = arr[maxIndex]
arr[maxIndex] = arr[i]
arr[i] = temp
}
return arr
}
插入排序
插入排序是最好理解的一种排序算法,就是将未排序的元素,插入到已排序的序列里。
算法思想:首先把第一个元素归为已排序序列,然后从第二个元素开始,在已排序的序列中找到第一个小于该元素的值,将元素插入到这个值后面。
代码实现:
function insertionSort(arr) {
for(let i = 1; i < arr.length; i++) {
let unSorted = arr[i]
let j = i - 1;
while(j >= 0 && arr[j] > unSorted) {
console.log(j)
arr[j + 1] = arr[j]
j --;
}
console.log(i)
arr[j + 1] = unSorted
}
return arr
}
快速排序
快速排序基本上是面试必考的排序算法,也是实践中最常用到的算法,公认的最快的排序算法之一。
算法思想:在数组中选择一个元素作为”基准”值(通常为第一个),把小于”基准”的元素放在前面,大于”基准”的元素放在后面,这样就完成一次快速排序。然后对”基准”左边和右边的两个子集,不断重复上述过程,知道所有子集只剩下一个元素为止。
代码实现:
function quickSort(arr, left = 0, right = arr.length - 1) {
let pivot = arr[left] // 基准值
let i = left // 左边界
let j = right // 右边界
while(i < j) {
while(arr[j] > pivot && i < j) {
j--
}
if(arr[j] < pivot) {
swap(arr, i, j)
}
while(arr[i] <= pivot && i < j) {
i++
}
if(arr[i] > pivot) {
swap(arr, i, j)
}
// i 和 j相遇,即产生一个分界点,然后分别对该分界点的左右两个子集重复排序。
if(i === j) {
quickSort(arr, left, i - 1)
quickSort(arr, i + 1, right)
break
}
}
// 交换函数
function swap(arr, i, j) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}