面试算法题之排序(上)

145

一、前端为什么学算法

下面直接给出让人无法反驳的一些理由

  1. 各种大厂面试硬性要求面试算法
  2. 精通算法能更好的阅读一些框架的源码,比如react、vue中的diff计算
  3. 算法能使你的思想更加灵活
  4. 你是否想做一辈子的增删改查

二、冒泡、插入、选择

冒泡排序

  • 概念:冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求。如果不满足就让它俩互换。一次冒泡会让至少一个元素移动到它应该在的位置,重复 n 次,就完成了 n 个数据的排序工作。
  • 时间复杂度 O(n2)
  • 空间复杂度 O(1)
  • 代码实现(从小到大),两层for循环,第一层表示冒泡次数,第二层对比相邻元素,第二次遍历需要注意的是已经冒泡过的元素不在需要遍历
function bubbleSort(target) {
    if (!target || !target instanceof Array || target.length < 2) {
    	return target || []
    }
    let len = target.length
    // 遍历len次,即经过len次冒泡
    for (let i=0; i<len; i++) {
    	let isDone = false
        // j < len- i - 1是因为len - i -1及之后的肯定比之前的都大
    	for(let j=0; j<len - i - 1; j ++) { 
            if (target[j] < target[j + 1]) {
            	// 每次循环把此次中最大的移到相应的位置,交换位置
                let tem = target[j]
                target[j] = target[j + 1]
                target[j + 1] = tem
                isDone = true
            }
        }
        // 如果此次循环没有交换位置,则表示已经排序结束
        if (!isDone) break
    }
}

插入排序

  • 概念:将数组分为有空间和无序空间,有序空间初始值为数组第一项,取出无序空间一项,插入到有序空间中合适的位置,循环n遍,就可以得到一个有序数组
  • 时间复杂度O(n2)
  • 空间复杂度O(1)
  • 代码实现(从小到大),两层for循环,第一次遍历无序空间,第二层遍历有序空间,将元素插入合适的位置(包含移动和插入)
function insertSort(target) {
    if (!target || !target instanceof Array || target.length < 2) {
    	return target || []
    }
    let len = target.length
    // 遍历无序空间
    for(let i=1; i<len; i++) {
        let value = target[i]
        let j = i - 1
        for(; j>=0; --j) {
            // 第二次循环遍历有序空间
            if(target[j] > value) {
                // 如果value < target[j],将target[j]后移一位
                target[j + 1] = target[j]
            } else break
        }
        target[j + 1] = value // 插入数据
    }
    return target
}

选择排序

  • 概念:选择排序算法的实现思路有点类似插入排序,也分有序空间和无序空间。但是选择排序每次会从无序空间中找到最小的元素,将其放到有序空间的末尾,即找到最小元素和i元素交换位置。
  • 时间复杂度 O(n2)
  • 空间复杂度 O(1)
  • 代码实现(从小到大),两层for循环,第一层遍历所有元素,交换位置,第二层,找出最小元素
function selectSort(target) {
    if (!target || !target instanceof Array || target.length < 2) {
    	return target || []
    }
    for(let i=0; i<target.length; i++){
        let minIndex = i
        // 循环找出最小元素
        for(let j=i+1; j<target.length; j++){
            if(target[j] < target[minIndex]){
                minIndex = j
            }
        }
        let tem = target[i]
        target[i] = target[minIndex]
        target[minIndex] = tem
    }
    return target
}