Skip to content

排序算法全解析 🚀

本文详细介绍常见的排序算法,包括原理解析、代码实现、性能分析等,帮助前端开发者更好地理解和应用这些算法。

目录 📑

  1. 冒泡排序
  2. 选择排序
  3. 插入排序
  4. 希尔排序
  5. 归并排序
  6. 快速排序
  7. 堆排序

冒泡排序 🫧

1. 算法思想

想象一下冒泡的过程:

  • 就像气泡在水中上升一样,较大的数字会不断"上浮"到数组的右侧
  • 通过相邻元素的比较和交换,每一轮都会将当前最大的数字冒泡到正确的位置
  • 经过 n-1 轮冒泡后,数组就完成了排序

2. 代码实现与详解

js
/**
 * 冒泡排序
 * 时间复杂度: O(n²)
 * 空间复杂度: O(1)
 * 稳定性: 稳定
 */
for (let i = 0; i < arr.length; i++) {
    let flag = true  // 优化点:标记本轮是否发生交换
    for (let j = 0; j < arr.length - i - 1; j++) {
        // 相邻元素比较,大的上浮
        if (arr[j] > arr[j + 1]) {
            [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]  // ES6解构赋值交换
            flag = false  // 发生了交换,标记为false
        }
    }
    // 如果一轮下来没有交换,说明已经有序
    if(flag) break
}

3. 图解过程

初始数组: [5, 3, 8, 4, 2]

第一轮:
[3, 5, 8, 4, 2] ← 5和3交换
[3, 5, 8, 4, 2] ← 5和8不交换
[3, 5, 4, 8, 2] ← 8和4交换
[3, 5, 4, 2, 8] ← 8和2交换
结果:最大值8已到达正确位置

第二轮:
[3, 5, 4, 2, 8]
[3, 4, 5, 2, 8] ← 5和4交换
[3, 4, 2, 5, 8] ← 5和2交换
...

4. 性能分析

指标结果说明
时间复杂度O(n²)两层嵌套循环
空间复杂度O(1)只需要一个临时变量
稳定性稳定相等元素不会交换位置

5. 优化思路

  1. 添加 flag 标志位,当某轮没有交换时提前退出
  2. 记录最后一次交换的位置,减少比较范围
  3. 同时从两端进行冒泡(鸡尾酒排序)

选择排序 🎯

1. 算法思想

想象你在整理扑克牌:

  • 从未排序区域找到最小的牌
  • 将它放到已排序区域的末尾
  • 重复这个过程直到所有牌都排好序

2. 代码实现与详解

js
/**
 * 选择排序
 * 时间复杂度: O(n²)
 * 空间复杂度: O(1)
 * 稳定性: 不稳定
 */
let index
for (let i = 0; i < arr.length; i++) {
    index = i  // 记录最小值的索引
    // 在未排序区域寻找最小值
    for (let j = i + 1; j < arr.length; j++) {
        if (arr[j] < arr[index]) {
            index = j
        }
    }
    // 如果找到比当前位置更小的元素,交换它们
    if (index != i) {
        // 使用异或运算进行交换,无需额外空间
        arr[i] = arr[i] ^ arr[index]
        arr[index] = arr[i] ^ arr[index]
        arr[i] = arr[i] ^ arr[index]
    }
}

插入排序 🎯

1. 算法思想

想象你在打扑克牌:

  • 每次抓到一张新牌时,都要将它插入到手中已经排好序的牌中
  • 从右向左比较,找到合适的位置插入
  • 就像整理手中的扑克牌一样,逐步构建有序序列

💡 插入排序对于小规模数据或基本有序的数据特别高效

2. 代码实现与详解

js
/**
 * 插入排序
 * @param {number[]} arr - 待排序数组
 * @returns {number[]} - 排序后的数组
 * 时间复杂度: O(n²)
 * 空间复杂度: O(1)
 * 稳定性: 稳定
 */
function insertionSort(arr) {
    const len = arr.length;
    // 从第二个元素开始,因为第一个元素可以认为已经被排序
    for (let i = 1; i < len; i++) {
        // 保存当前要插入的元素
        const current = arr[i];
        let j = i - 1;
        
        // 寻找插入位置
        while (j >= 0 && arr[j] > current) {
            // 将较大的元素都向右移动一位
            arr[j + 1] = arr[j];
            j--;
        }
        
        // 插入到正确位置
        arr[j + 1] = current;
    }
    return arr;
}

3. 图解过程

初始数组: [5, 3, 8, 4, 2]

第一轮: 3要插入到已排序区域[5]中
[5, 3, 8, 4, 2] → [3, 5, 8, 4, 2]

第二轮: 8要插入到已排序区域[3, 5]中
[3, 5, 8, 4, 2] → [3, 5, 8, 4, 2] (无需移动)

第三轮: 4要插入到已排序区域[3, 5, 8]中
[3, 5, 8, 4, 2] → [3, 4, 5, 8, 2]

第四轮: 2要插入到已排序区域[3, 4, 5, 8]中
[3, 4, 5, 8, 2] → [2, 3, 4, 5, 8]

4. 前端实际应用

js
/**
 * 实际应用:对用户列表按注册时间排序
 */
class UserList {
    constructor() {
        this.users = [];
    }
    
    addUser(user) {
        // 使用插入排序保持用户列表按注册时间有序
        const newUser = {
            ...user,
            registerTime: new Date(user.registerTime)
        };
        
        let i = this.users.length - 1;
        while (i >= 0 && 
               this.users[i].registerTime > newUser.registerTime) {
            this.users[i + 1] = this.users[i];
            i--;
        }
        this.users[i + 1] = newUser;
    }
}

// 使用示例
const userList = new UserList();
userList.addUser({
    name: 'Tom',
    registerTime: '2023-01-01'
});
userList.addUser({
    name: 'Jerry',
    registerTime: '2023-02-01'
});

5. 性能分析

场景时间复杂度说明
最好情况O(n)数组已经有序
最坏情况O(n²)数组完全逆序
平均情况O(n²)随机顺序

6. 优化思路

  1. 二分查找优化:使用二分查找快速找到插入位置
  2. 希尔排序:通过增量分组进行优化
  3. 缓存机制:对频繁插入的场景使用缓存

希尔排序 🐚

1. 算法思想

希尔排序是插入排序的改进版:

  • 将数组按照一定间隔分组
  • 对每组使用插入排序
  • 逐步减小间隔,最后一轮间隔为1
  • 类似于"大步快跑,小步调整"

2. 代码实现

js
/**
 * 希尔排序
 * @param {number[]} arr - 待排序数组
 * @returns {number[]} - 排序后的数组
 * 时间复杂度: O(n^1.3)
 * 空间复杂度: O(1)
 * 稳定性: 不稳定
 */
function shellSort(arr) {
    const len = arr.length;
    // 初始间隔设为长度的一半
    let gap = Math.floor(len / 2);
    
    while (gap > 0) {
        // 对每个分组进行插入排序
        for (let i = gap; i < len; i++) {
            const temp = arr[i];
            let j = i;
            
            // 组内插入排序
            while (j >= gap && arr[j - gap] > temp) {
                arr[j] = arr[j - gap];
                j -= gap;
            }
            
            arr[j] = temp;
        }
        
        // 缩小间隔
        gap = Math.floor(gap / 2);
    }
    
    return arr;
}

归并排序 🔄

1. 算法思想

想象你在整理一摞扑克牌:

  • 将牌分成两堆
  • 分别整理好每一堆
  • 最后将两堆有序的牌合并成一堆
  • 这就是"分而治之"的思想

💡 归并排序的核心是:先分解,后合并。就像公司处理大项目时,先拆分成小组任务,各组完成后再整合。

2. 代码实现与详解

js
/**
 * 归并排序
 * @param {number[]} arr - 待排序数组
 * @returns {number[]} - 排序后的数组
 * 时间复杂度: O(nlogn)
 * 空间复杂度: O(n)
 * 稳定性: 稳定
 */
function mergeSort(arr) {
    // 基础情况:数组长度为1时已经有序
    if (arr.length <= 1) return arr;
    
    // 分解:将数组分成两半
    const mid = Math.floor(arr.length / 2);
    const left = arr.slice(0, mid);
    const right = arr.slice(mid);
    
    // 递归排序左右两半
    return merge(
        mergeSort(left), 
        mergeSort(right)
    );
}

/**
 * 合并两个有序数组
 * @param {number[]} left - 左半部分
 * @param {number[]} right - 右半部分
 * @returns {number[]} - 合并后的有序数组
 */
function merge(left, right) {
    const result = [];
    let leftIndex = 0;
    let rightIndex = 0;
    
    // 比较两个数组的元素,将较小的放入结果数组
    while (leftIndex < left.length && rightIndex < right.length) {
        if (left[leftIndex] <= right[rightIndex]) {
            result.push(left[leftIndex]);
            leftIndex++;
        } else {
            result.push(right[rightIndex]);
            rightIndex++;
        }
    }
    
    // 将剩余元素添加到结果数组
    return result
        .concat(left.slice(leftIndex))
        .concat(right.slice(rightIndex));
}

3. 图解过程

原始数组: [5, 3, 8, 4, 2, 7, 1, 6]

分解过程:
[5, 3, 8, 4 | 2, 7, 1, 6]
[5, 3 | 8, 4] [2, 7 | 1, 6]
[5 | 3] [8 | 4] [2 | 7] [1 | 6]

合并过程:
[3, 5] [4, 8] [2, 7] [1, 6]
[3, 4, 5, 8] [1, 2, 6, 7]
[1, 2, 3, 4, 5, 6, 7, 8]

4. 前端实战应用

js
/**
 * 实际应用:合并多个有序请求结果
 */
class RequestMerger {
    /**
     * 合并多个分页请求的结果
     * @param {Promise[]} requests - 请求数组
     * @returns {Promise<Array>} - 合并后的有序结果
     */
    static async mergeRequests(requests) {
        try {
            // 并行执行所有请求
            const results = await Promise.all(requests);
            
            // 合并所有有序结果
            return results.reduce((merged, current) => {
                return this.merge(merged, current);
            }, []);
            
        } catch (error) {
            console.error('合并请求失败:', error);
            throw error;
        }
    }
    
    /**
     * 合并两个有序数组
     */
    static merge(arr1, arr2) {
        const result = [];
        let i = 0, j = 0;
        
        while (i < arr1.length && j < arr2.length) {
            if (arr1[i].timestamp <= arr2[j].timestamp) {
                result.push(arr1[i++]);
            } else {
                result.push(arr2[j++]);
            }
        }
        
        return result
            .concat(arr1.slice(i))
            .concat(arr2.slice(j));
    }
}

// 使用示例
async function getOrderedData() {
    const requests = [
        fetch('/api/data?page=1'),
        fetch('/api/data?page=2'),
        fetch('/api/data?page=3')
    ];
    
    const mergedData = await RequestMerger.mergeRequests(requests);
    return mergedData;
}

5. 性能分析

场景时间复杂度空间复杂度说明
最好情况O(nlogn)O(n)任何情况下都是
最坏情况O(nlogn)O(n)任何情况下都是
平均情况O(nlogn)O(n)任何情况下都是

6. 优化思路

  1. 小规模数组使用插入排序
  2. 原地归并减少空间使用
  3. 并行化处理大数据集
  4. 缓存临时数组避免频繁分配

快速排序 ⚡

1. 算法思想

想象你在整理书架:

  • 先选一本基准书(pivot)
  • 把比基准书薄的放左边,厚的放右边
  • 对左右两边的书重复这个过程
  • 最终书架就按厚度排好序了

💡 快速排序是实际应用中最常用的排序算法,V8引擎的 Array.prototype.sort() 就使用了快排的思想。

2. 代码实现与详解

js
/**
 * 快速排序
 * @param {number[]} arr - 待排序数组
 * @returns {number[]} - 排序后的数组
 * 时间复杂度: 平均 O(nlogn),最坏 O(n²)
 * 空间复杂度: O(logn)
 * 稳定性: 不稳定
 */
function quickSort(arr, left = 0, right = arr.length - 1) {
    if (left < right) {
        // 获取分区点
        const pivotIndex = partition(arr, left, right);
        
        // 递归排序左右两部分
        quickSort(arr, left, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, right);
    }
    return arr;
}

/**
 * 分区函数
 * @param {number[]} arr - 待分区数组
 * @param {number} left - 左边界
 * @param {number} right - 右边界
 * @returns {number} - 基准元素的最终位置
 */
function partition(arr, left, right) {
    // 选择最右边的元素作为基准
    const pivot = arr[right];
    // i 是小于基准区域的边界
    let i = left - 1;
    
    // 将小于基准的元素移到左边
    for (let j = left; j < right; j++) {
        if (arr[j] <= pivot) {
            i++;
            [arr[i], arr[j]] = [arr[j], arr[i]];
        }
    }
    
    // 将基准元素放到正确的位置
    [arr[i + 1], arr[right]] = [arr[right], arr[i + 1]];
    return i + 1;
}

3. 优化版本

js
/**
 * 优化的快速排序
 * 1. 三数取中选择基准
 * 2. 小数组使用插入排序
 * 3. 处理重复元素
 */
function optimizedQuickSort(arr, left = 0, right = arr.length - 1) {
    // 小数组使用插入排序
    if (right - left <= 10) {
        return insertionSort(arr, left, right);
    }
    
    // 三数取中选择基准
    const mid = Math.floor((left + right) / 2);
    if (arr[left] > arr[mid]) {
        [arr[left], arr[mid]] = [arr[mid], arr[left]];
    }
    if (arr[left] > arr[right]) {
        [arr[left], arr[right]] = [arr[right], arr[left]];
    }
    if (arr[mid] > arr[right]) {
        [arr[mid], arr[right]] = [arr[right], arr[mid]];
    }
    
    const pivot = arr[mid];
    
    // 三路快排处理重复元素
    let lt = left;     // less than pivot
    let gt = right;    // greater than pivot
    let i = left + 1;  // current element
    
    while (i <= gt) {
        if (arr[i] < pivot) {
            [arr[lt], arr[i]] = [arr[i], arr[lt]];
            lt++;
            i++;
        } else if (arr[i] > pivot) {
            [arr[gt], arr[i]] = [arr[i], arr[gt]];
            gt--;
        } else {
            i++;
        }
    }
    
    // 递归排序左右两部分
    optimizedQuickSort(arr, left, lt - 1);
    optimizedQuickSort(arr, gt + 1, right);
    
    return arr;
}

4. 前端实战应用

js
/**
 * 实际应用:文件大小排序
 */
class FileSystem {
    constructor() {
        this.files = [];
    }
    
    /**
     * 添加文件
     * @param {Object} file - 文件对象
     */
    addFile(file) {
        this.files.push({
            name: file.name,
            size: file.size,
            type: file.type,
            lastModified: file.lastModified
        });
    }
    
    /**
     * 获取按大��排序的文件列表
     * @returns {Array} - 排序后的文件列表
     */
    getSortedBySize() {
        return quickSort([...this.files], 0, this.files.length - 1);
    }
    
    /**
     * 自定义比较函数的快速排序
     */
    customSort(compareFunc) {
        const sort = (arr, left, right) => {
            if (left >= right) return;
            
            const pivot = arr[right];
            let i = left - 1;
            
            for (let j = left; j < right; j++) {
                if (compareFunc(arr[j], pivot) <= 0) {
                    i++;
                    [arr[i], arr[j]] = [arr[j], arr[i]];
                }
            }
            
            [arr[i + 1], arr[right]] = [arr[right], arr[i + 1]];
            
            sort(arr, left, i);
            sort(arr, i + 2, right);
        };
        
        const newFiles = [...this.files];
        sort(newFiles, 0, newFiles.length - 1);
        return newFiles;
    }
}

// 使用示例
const fs = new FileSystem();
fs.addFile({name: 'doc.pdf', size: 1024});
fs.addFile({name: 'img.jpg', size: 2048});

// 按大小排序
const sizeSort = fs.getSortedBySize();

// 自定义排序(按名称)
const nameSort = fs.customSort((a, b) => 
    a.name.localeCompare(b.name)
);

5. 性能分析

场景时间复杂度原因
最好情况O(nlogn)每次都平均分割
最坏情况O(n²)已经有序或逆序
平均情况O(nlogn)随机数据

6. 优化思路

  1. 三数取中选择基准
  2. 小数组使用插入排序
  3. 三路快排处理重复元素
  4. 随机选择基准元素
  5. 尾递归优化

7. 注意事项 ⚠️

  1. 基准元素的选择会影响性能
  2. 处理重复元素时需要特别注意
  3. 递归深度可能导致栈溢出
  4. 不稳定性可能影响某些应用场景

堆排序 🌳

1. 算法思想

想象一个公司的组织架构:

  • CEO在顶层,管理整个团队
  • 每个经理管理自己的小组
  • 调整时,高管可能下调,基层员工可能升职
  • 这就像堆的调整过程

💡 堆排序利用了完全二叉树的特性,通过构建最大堆,不断将最大元素放到数组末尾来实现排序。

2. 基本概念

  1. 完全二叉树:除了最后一层,其他层都是满的,最后一层的节点都靠左排列
  2. 最大堆:父节点总是大于或等于子节点
  3. 节点关系:
    • 父节点索引:Math.floor((i-1)/2)
    • 左子节点索引:2*i + 1
    • 右子节点索引:2*i + 2

3. 代码实现与详解

js
/**
 * 堆排序
 * @param {number[]} arr - 待排序数组
 * @returns {number[]} - 排序后的数组
 * 时间复杂度: O(nlogn)
 * 空间复杂度: O(1)
 * 稳定性: 不稳定
 */
function heapSort(arr) {
    const len = arr.length;
    
    // 构建最大堆
    // 从最后一个非叶子节点开始向上调整
    for (let i = Math.floor(len/2) - 1; i >= 0; i--) {
        heapify(arr, len, i);
    }
    
    // 排序过程
    for (let i = len - 1; i > 0; i--) {
        // 将堆顶(最大值)交换到数组末尾
        [arr[0], arr[i]] = [arr[i], arr[0]];
        // 重新调整堆
        heapify(arr, i, 0);
    }
    
    return arr;
}

/**
 * 调整堆
 * @param {number[]} arr - 待调整的数组
 * @param {number} n - 堆的大小
 * @param {number} i - 当前节点索引
 */
function heapify(arr, n, i) {
    let largest = i;  // 假设当前节点最大
    const left = 2 * i + 1;  // 左子节点
    const right = 2 * i + 2; // 右子节点
    
    // 如果左子节点比当前节点大
    if (left < n && arr[left] > arr[largest]) {
        largest = left;
    }
    
    // 如果右子节点比最大值还大
    if (right < n && arr[right] > arr[largest]) {
        largest = right;
    }
    
    // 如果最大值不是当前节点,交换并继续调整
    if (largest !== i) {
        [arr[i], arr[largest]] = [arr[largest], arr[i]];
        heapify(arr, n, largest);
    }
}

4. 图解过程

原始数组: [4, 10, 3, 5, 1]

构建最大堆:
     4               10              10
    / \             / \             / \
   10  3    =>     4   3    =>     5   3
  / \             / \             / \
 5   1           5   1           4   1

排序过程:
     10              1               1
    / \             / \             / \
   5   3    =>     5   3    =>     4   3
  / \             / \             /
 4   1           4   10          5   10

5. 前端实战应用

js
/**
 * 实际应用:任务优先级队列
 */
class PriorityQueue {
    constructor() {
        this.queue = [];
    }
    
    /**
     * 添加任务
     * @param {Object} task - 任务对象
     * @param {number} priority - 优先级(1-5)
     */
    enqueue(task, priority) {
        this.queue.push({ task, priority });
        this._bubbleUp(this.queue.length - 1);
    }
    
    /**
     * 获取最高优先级任务
     */
    dequeue() {
        if (this.queue.length === 0) return null;
        
        const top = this.queue[0];
        const last = this.queue.pop();
        
        if (this.queue.length > 0) {
            this.queue[0] = last;
            this._sinkDown(0);
        }
        
        return top.task;
    }
    
    /**
     * 向上调整
     */
    _bubbleUp(index) {
        while (index > 0) {
            const parentIndex = Math.floor((index - 1) / 2);
            if (this.queue[parentIndex].priority >= 
                this.queue[index].priority) {
                break;
            }
            
            [this.queue[parentIndex], this.queue[index]] = 
            [this.queue[index], this.queue[parentIndex]];
            
            index = parentIndex;
        }
    }
    
    /**
     * 向下调整
     */
    _sinkDown(index) {
        const length = this.queue.length;
        while (true) {
            let highestPriority = index;
            const leftChild = 2 * index + 1;
            const rightChild = 2 * index + 2;
            
            if (leftChild < length && 
                this.queue[leftChild].priority > 
                this.queue[highestPriority].priority) {
                highestPriority = leftChild;
            }
            
            if (rightChild < length && 
                this.queue[rightChild].priority > 
                this.queue[highestPriority].priority) {
                highestPriority = rightChild;
            }
            
            if (highestPriority === index) break;
            
            [this.queue[index], this.queue[highestPriority]] = 
            [this.queue[highestPriority], this.queue[index]];
            
            index = highestPriority;
        }
    }
}

// 使用示例
const taskQueue = new PriorityQueue();

taskQueue.enqueue({
    id: 1,
    name: '紧急bug修复'
}, 5);

taskQueue.enqueue({
    id: 2,
    name: '新功能开发'
}, 3);

taskQueue.enqueue({
    id: 3,
    name: '代码优化'
}, 1);

console.log(taskQueue.dequeue()); // 输出:紧急bug修复

6. 性能分析

操作时间复杂度说明
建堆O(n)从最后一个非叶子节点开始调整
调整O(logn)树的高度决定
整体排序O(nlogn)n次调整操作

7. 优化思路

  1. 数组预分配空间
  2. 迭代代替递归
  3. 批量建堆优化
  4. 缓存计算结果

8. 注意事项 ⚠️

  1. 堆是完全二叉树,不要破坏这个性质
  2. 注意索引计算的边界条件
  3. 父子节点的关系要始终保持
  4. 调整过程要考虑连锁反应

9. 练习题推荐 📝

  1. LeetCode 215: 数组中的第K个最大元素
  2. LeetCode 347: 前K个高频元素
  3. LeetCode 23: 合并K个排序链表
  4. LeetCode 295: 数据流的中位数

总结与对比 📊

1. 排序算法对比表

排序算法平均时间复杂度最坏时间复杂度空间复杂度稳定性适用场景
冒泡排序O(n²)O(n²)O(1)稳定小数据量、近乎有序
选择排序O(n²)O(n²)O(1)不稳定小数据量、对稳定性无要求
插入排序O(n²)O(n²)O(1)稳定小数据量、近乎有序
希尔排序O(n^1.3)O(n²)O(1)不稳定中等数据量
归并排序O(nlogn)O(nlogn)O(n)稳定大数据量、要求稳定
快速排序O(nlogn)O(n²)O(logn)不稳定大数据量、通用场景
堆排序O(nlogn)O(nlogn)O(1)不稳定大数据量、求TopK

2. 如何选择排序算法?🤔

  1. 数据规模考虑

    • 小规模数据(n < 50):插入排序
    • 中等规模数据:快速排序
    • 大规模数据:归并排序(稳定)或快速排序(高效)
  2. 数据特征考虑

    • 近乎有序:插入排序
    • 完全随机:快速排序
    • 重复元素多:三路快排
    • 对象排序:归并排序(稳定性好)
  3. 环境限制考虑

    • 内存受限:堆排序
    • CPU密集:快速排序
    • 要求稳定:归并排序
    • 并行处理:归并排序

3. 前端开发中的实际应用 💻

  1. 数据表格排序
js
/**
 * 表格排序工具类
 */
class TableSorter {
    constructor() {
        this.sortStrategies = {
            number: (a, b) => a - b,
            string: (a, b) => a.localeCompare(b),
            date: (a, b) => new Date(a) - new Date(b)
        };
    }

    /**
     * 对表格数据进行排序
     * @param {Array} data - 表格数据
     * @param {string} column - 排序列
     * @param {string} type - 数据类型
     * @param {boolean} ascending - 是否升序
     */
    sort(data, column, type = 'string', ascending = true) {
        const comparator = this.sortStrategies[type];
        return [...data].sort((a, b) => {
            const result = comparator(a[column], b[column]);
            return ascending ? result : -result;
        });
    }
}

// 使用示例
const sorter = new TableSorter();
const tableData = [
    { name: 'John', age: 30, date: '2023-01-01' },
    { name: 'Alice', age: 25, date: '2023-02-01' }
];

// 按年龄排序
const ageSorted = sorter.sort(tableData, 'age', 'number', true);
  1. 文件列表排序
js
/**
 * 文件排序工具类
 */
class FileSorter {
    /**
     * 按不同维度排序文件
     * @param {Array} files - 文件列表
     * @param {string} sortBy - 排序维度
     */
    static sort(files, sortBy = 'name') {
        const strategies = {
            name: (a, b) => a.name.localeCompare(b.name),
            size: (a, b) => a.size - b.size,
            date: (a, b) => new Date(b.lastModified) - new Date(a.lastModified),
            type: (a, b) => a.type.localeCompare(b.type)
        };

        return [...files].sort(strategies[sortBy]);
    }
}

4. 性能优化建议 ⚡

  1. 通用优化

    • 小数组使用插入排序
    • 预处理数据减少比较成本
    • 利用数据特征选择合适算法
  2. 前端特定优化

    • 大数据量考虑分页排序
    • 利用 Web Worker 处理排序
    • 缓存排序结果
    • 使用虚拟列表展示

5. 学习建议 📚

  1. 掌握基础

    • 理解每种排序算法的核心思想
    • 熟练手写快排和归并排序
    • 理解稳定性的概念和应用
  2. 进阶提升

    • 学习高级优化技巧
    • 理解排序算法的取舍
    • 结合实际场景练习
  3. 实战应用

    • 多写demo
    • 阅读开源代码
    • 结合业务场景实践

6. 推荐资源 📖

  1. 在线练习平台

    • LeetCode 排序专题
    • 牛客网编程题
    • CodeWars
  2. 推荐书籍

    • 《算法》(第4版)
    • 《JavaScript数据结构与算法》
    • 《编程珠玑》
  3. 在线可视化工具

希望这篇文章能帮助你更好地理解和应用排序算法!如果有任何问题,欢迎讨论交流。 🎉