javascript 算法之 排序搜索 必出精品

251 阅读3分钟

1、介绍

2、JS实现冒泡排序 (比较简单工作遇不到面试常见) O(n ^ 2)

  • 我们先在数组原型上挂一个bubbleSort
// 数组原型上挂一个bubbleSort 方法
Array.prototype.bubbleSort = function(){
    console.log(this)
}

var arr = [1,2,3]
arr.bubbleSort()   //[1,2,3]

  • 获取所有相邻元素
// 数组原型上挂一个bubbleSort 方法
Array.prototype.bubbleSort = function(){
    // console.log(this)
    for(let j = 0; j < this.length - 1; j ++){
        console.log(this[j],this[j+1])   // 得到了相邻元素 1  2     2  3
    }
}

var arr = [1,2,3]
arr.bubbleSort()   //[1,2,3]
  • 需要两个循环 先写好内层的j循环 保证第一个元素 到最后
  • 外层 i 循环 保证 每个元素都到对应的位置
// 数组原型上挂一个bubbleSort 方法
Array.prototype.bubbleSort = function(){
    // console.log(this)
    // 外层这个i循环主要保证每个元素都换到合适的位置
    for(let i = 0; i < this.length - 1;i++){
        //内层这个j循环保证第一个元素换到最后 并且 由于交换后 其他元素交换区间变小  j < this.length - 1 -i
        for(let j = 0; j < this.length - 1 - i; j ++){
            // console.log(this[j],this[j+1])   // 得到了相邻元素 1  2     2  3
            //相邻比较后交换
            if(this[j] > this[j+1]){
                const temp = this[j]
                this[j] = this[j+1]
                this[j+1] = temp
            }
         }
    }
    
}

var arr = [5,4,3,2,1]
arr.bubbleSort()     //[1,2,3,4,5]

3、JS 实现选择排序 O(n ^ 2)

  • 思路稍微 比冒泡排序多一点 不过 也是比较容易理清楚的
  • 如果有问题 建议再理解一下 打几个断点
Array.prototype.selectionSort = function(){
    // 外层循环的作用是执行 n-1轮 所以长度是this.length -1
    // 需要将内层循环中的0 都改成 i 因为比较的数组再变小
    // 还有一个当 indexMin === i就是自身不需要交换加个 if 
    for(var i = 0; i < this.length -1; i++){
        // 假设最小元素的索引是第一个元素
    var indexMin = i
    for(var j = i; j < this.length; j ++){
        // 判断一下 如果遍历当前元素小于第一个元素则将最小值的索引改成当前元素索引 j
        if(this[j] < this[indexMin]){
            indexMin = j
        }
    }
    // 交换当前元素和第一个元素
    if(indexMin !== i){
    var temp = this[i]
    this[i] = this[indexMin]
    this[indexMin] = temp
    }
    
    }
    
}

var arr = [5,4,3,2,1]
arr.selectionSort()  // [1,2,3,4,5]


4、 JS 插入排序 O(n^2)

  • 也是两个 for循环
  • 需要注意的是 从第二个数开始 向前比较
Array.prototype.insertionSort = function(){
    //外层i 循环 是进行其他数比较 注意 i从 1开始
    // 将里面的0 换成 i
    for(var i = 1; i < this.length; i ++){
        // 因为是拿到第二个数进行比较 this[1]第一个数是 this[0]
    var temp = this[i]
    var j = i
    while(j>0){
        if(this[j - 1] > temp){
            this[j] = this[j - 1]
        }else{
            break
        }
        j --

    }
    this[j] = temp
    }
    
}

var arr = [5,4,3,2,1]
arr.insertionSort()  // [1,2,3,4,5]


5、JS 归并排序 O(NlogN)

  • 听名字有点陌生 怎么实现 请看下文
  • 尝试写一下代码 实现一下 这个过程
1、将数组分成左右两部分 并递归  需要使用 slice(0,mid) slice(mid,arr.length) 分开两个数组
2、新建res,比较两个数组队头 较小者 出对并放入 res中  注意中途对比 .length 不要忘了
3、结果 拷贝到this
  这里是this this[i]=n  不要写成 res
Array.prototype.mergeSort = function(){
    var rec = (arr) => {
        if(arr.length === 1) {return arr}
        // 拿到数组中间数 
        var mid = Math.floor(arr.length / 2 )
        // 分为左边和右边并递归
        var left = arr.slice(0,mid)
        var right = arr.slice(mid,arr.length)
        var orderLeft = rec(left)
        var orderRight = rec(right)
        // 新建结果数组res
        var res = []
        // 比较两个有序数组头部 较小者出队并 推入 res中
        while(orderLeft.length || orderRight.length){
            if(orderLeft.length && orderRight.length){
                res.push(orderLeft[0] < orderRight[0] ? orderLeft.shift() : orderRight.shift())
        // 如果 右边的数组已经空了 把左边剩余元素放入res中
            }else if(orderLeft.length){
                res.push(orderLeft.shift())
            }else if(orderRight.length){
                res.push(orderRight.shift())
            }
        }
        return res
    }
    // 拷贝 结果到 this上
    var res = rec(this)
    res.forEach((n,i)=>{this[i] = n})
}

var arr =  [5,4,3,2,1]
arr.mergeSort()    // [1,2,3,4,5]



  • 敲一手 不是不困难
  • 试试呗 看不懂我给你出个视频
  • visualgo.net/en/sorting 再给你个好东西 可以看每个算法时间复杂度

6、JS 快速排序 O(nlogN)

  • 工作常用
Array.prototype.quickSort = function(){
    // 递归
    var rec = (arr)=>{
        //递归需要的终止条件  这两个都是 需要的 否则会陷入 无限循环
        if (arr.length === 0) return arr
        if(arr.length === 1){return arr}
        //写左右分区
        var left = []
        var right = []
        // 设置基准
        var mid = arr[0]
        //循环 比基准小的放在左边 比基准大的放在右边
        for(var i = 1; i < arr.length; i ++){
            if(arr[i] < mid){
                left.push(arr[i])
            }else{
                right.push(arr[i])
            }
        }
        // 使用rest运算符连接整个数组
        return [...rec(left),mid,...rec(right)]
    }
    // 结果给this
    var res = rec(this)
    res.forEach((n,i)=>{this[i] = n})
}

var arr = [2,9,3,1,6]
arr.quickSort()


7、JS 顺序排序 O(n)

  • 如果数组很大的话 很 低效 算法入门
Array.prototype.Search = function(item){
    for(var i = 0; i < this.length; i++){
        // item为传入的目标值 和当前便利值匹配
        // 返回匹配下标
        if(this[i] == item){
            return i
        }
    }   
    return -1
}

var res = [1,2,5,4,7].Search(2)    //2

  • 可以找到指定数的 下标位置

8、JS 二分搜索 时间复杂度O(logn)

* 前提需要是 排序好的数组 未排序需要先排序

// 二分搜索
Array.prototype.binarySearch =  function(item){
    // 首先 拿到最小下标 最大下标 
    var low  = 0
    var high = this.length - 1
    
    while(low <= high){
    var mid = Math.floor((low+high)/2)
    //拿到中间下标的下标值
    var element = this[mid]
        if(element > item){
            high = mid - 1
        }else if(element < item){
            low = mid + 1
        }else{
            return mid
        }
    }
    return -1
}

// test 
var res = [1,2,3,4,5].binarySearch(5)   // 4

* 就可快速找到 目标值 

9、 LeetCode:21. 合并两个有序链表

var mergeTwoLists = function(l1, l2) {
    // 链表实例化
    var res = new ListNode(0)
    // 需要3个指针 分别指向 res l1 l2
    var p = res
    var p1 = l1
    var p2 = l2
    // l1 l2 都有值的情况下
    while(p1 && p2){
        // 较小者 接在 res后面 
        if(p1.val > p2.val){
            p.next = p2
            p2 = p2.next
        }else{
            p.next = p1
            p1 = p1.next
        }
        // res的指针p也需要往下移动
        p = p.next
    }
    //p1 或者 p2 只有一个有值的情况下 直接接在res后面就行
    if(p1){
        p.next = p1
    }
    if(p2){
        p.next = p2
    }
    return res.next
};

10、LeetCode:374. 猜数字大小

  • 上代码 这个部分 是不是看起来很顺畅
//典型的二分搜索法
//时间复杂度 分成两半O(logN)   空间复杂度 O(1) 没有数组 堆栈 
var guessNumber = function(n) {
    // 最小最大下标
    var low = 1
    var high = n
    while(low <= high){
        var mid = Math.floor((low + high)/2)
        // 传入接口
        var res = guess(mid)
        // 可在此处输出测试一下  
        // console.log('mid',mid)
        // console.log('res',res)
        // 刚好题目给定的三种情况  不需要兜底 return -1
        if( res === 0){
            return mid
        }else if( res === -1){
            high = mid - 1
        }else{
            low = mid  + 1
        }
    }
};

11、小结