指南

算法

本文详细介绍了 JavaScript 中常见的排序和查找算法,适合前端初学者学习和实践。

🎯 引言

掌握这些基础算法后,你可以更好地理解数据在程序中的处理方式,提升代码效率,写出更高性能的前端程序。无论是对数据排序,还是从数据中快速查找目标,都能够得心应手。


🧮 排序算法详解

排序算法是前端开发中非常基础且重要的知识。它帮助我们把一组无序的数据变成有序,比如对商品价格排序,或者对时间线进行排列。

下面我们来聊聊几种经典且常用的排序算法。


冒泡排序 Bubble Sort

冒泡排序是最简单的排序算法。它的原理就是在数组中,从头到尾两两比较相邻元素,把大的往后“冒泡”。

想象一下,水里的气泡慢慢往上冒,越大的气泡越容易“浮”到顶部。

function bubbleSort(arr) {
    let len = arr.length;
    for (let i = 0; i < len - 1; i++) {
        for (let j = 0; j < len - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
            }
        }
    }
    return arr;
}

bubbleSort([5, 4, 2, 1, 3]); // [ 1, 2, 3, 4, 5 ]
冒泡排序的时间复杂度是 O(n²),对于数据量小的情况效果还可以,数据多时效率低。

选择排序 Selection Sort

选择排序的思路是每次找到数组中最小的那个元素,放到最前面。

可以想象你在挑选苹果,每次都找最小的拿出来放一边。

function selectionSort(arr) {
    let len = arr.length;
    for (let i = 0; i < len - 1; i++) {
        let minIndex = i;
        for (let j = i + 1; j < len; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        if (minIndex !== i) {
            [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
        }
    }
    return arr;
}

selectionSort([5, 4, 2, 1, 3]); // [ 1, 2, 3, 4, 5 ]
选择排序同样是 O(n²) 复杂度,不过交换次数少,适合交换代价高的场景。

插入排序 Insertion Sort

插入排序的思路是把数组分成已排序和未排序两部分,每次把未排序的第一个元素插入到已排序部分合适的位置。

就像整理扑克牌,把新牌插到合适的位置。

function insertionSort(arr) {
    let len = arr.length;
    for (let i = 1; i < len; i++) {
        let key = arr[i];
        let j = i - 1;
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
    return arr;
}

insertionSort([5, 4, 2, 1, 3]); // [ 1, 2, 3, 4, 5 ]
对于几乎有序的数组,插入排序效率很高,时间复杂度最坏情况下是 O(n²)。

快速排序 Quick Sort

快速排序是一种分治算法,它通过一个“基准”元素把数组分成两部分,一部分比基准小,另一部分比基准大,然后递归排序。

想象分组比赛,先把队伍按实力分成两组,再分别决出胜负。

function quickSort(arr) {
    if (arr.length <= 1) return arr;
    let pivot = arr[arr.length - 1];
    let left = [];
    let right = [];
    for (let i = 0; i < arr.length - 1; i++) {
        if (arr[i] < pivot) {
            left.push(arr[i]);
        } else {
            right.push(arr[i]);
        }
    }
    return [...quickSort(left), pivot, ...quickSort(right)];
}

quickSort([5, 4, 2, 1, 3]); // [ 1, 2, 3, 4, 5 ]
快速排序平均时间复杂度是 O(n log n),在大部分情况下表现很好,但最坏情况是 O(n²)。

归并排序 Merge Sort

归并排序也是分治思想,把数组一分为二,分别排序后合并。它很适合理解递归结构。

比喻为把一个大拼图拆成小块,分别拼好后再合并。

function mergeSort(arr) {
    if (arr.length <= 1) return arr;

    const mid = Math.floor(arr.length / 2);
    const left = mergeSort(arr.slice(0, mid));
    const right = mergeSort(arr.slice(mid));

    return merge(left, right);
}

function merge(left, right) {
    let result = [];
    let i = 0,
        j = 0;

    while (i < left.length && j < right.length) {
        if (left[i] < right[j]) {
            result.push(left[i++]);
        } else {
            result.push(right[j++]);
        }
    }

    return result.concat(left.slice(i)).concat(right.slice(j));
}

mergeSort([5, 4, 2, 1, 3]); // [ 1, 2, 3, 4, 5 ]
归并排序时间复杂度始终是 O(n log n),稳定性好,但需要额外空间。

🔍 查找算法详解

查找算法是前端中获取数据的常用操作。比如在列表中找某个用户,或者定位某条记录。


线性查找是最简单的查找方法,逐个遍历元素,找到目标就返回。

就像你翻书找某句话,一页一页往下看。

function linearSearch(arr, target) {
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] === target) {
            return i;
        }
    }
    return -1;
}

linearSearch([5, 4, 2, 1, 3], 1); // 3
线性查找适合无序数据,时间复杂度是 O(n),数据量大时效率低。

二分查找适合有序数组,先看中间元素,判断目标是在左边还是右边,再递归缩小范围。

就像你用字典查单词,先翻中间那页,对比大小后缩小查找范围。

function binarySearch(arr, target) {
    let left = 0;
    let right = arr.length - 1;

    while (left <= right) {
        let mid = Math.floor((left + right) / 2);
        if (arr[mid] === target) {
            return mid;
        } else if (arr[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }

    return -1;
}

binarySearch([1, 2, 3, 4, 5], 3); // 2
使用二分查找时请确保数组已排序,否则结果不准确。

🧾 小节总结

  • 冒泡、选择、插入排序适合小规模数据,理解简单但效率较低。
  • 快速排序和归并排序适合大规模数据,时间复杂度均为 O(n log n)。
  • 查找算法中,线性查找适合无序数据,二分查找适合有序数据,效率明显提升。

❓ 知识问答(Q&A)

Q:冒泡排序为什么效率低?

A:因为它需要多次比较和交换,时间复杂度是 O(n²),数据量大时运行慢。

Q:二分查找能用于无序数组吗?

A:不能,二分查找的前提条件是数组必须排序,否则无法保证左右半边的有序性。


🎉 恭喜你已经掌握 冒泡排序、快速排序、二分查找 等基础算法技能啦! 期待你用它们写出更高效的前端程序!