JavaScript数组基础算法

96 阅读7分钟

数组基础算法

数组去重

● 利用对象的键值对方法

// 1、我们把数组中的每一项的值当做一个对象的属性名和属性值存储起来
  //会改变原数组
  let arr = [1,2,3,4,5,1,2,3,4,5,6,2,3,4,1,42,42,52,34,3]
  let obj = {}
  for(let i = 0 ; i <arr.length; i++){
    let cur = arr[i]
    if(obj[cur] == cur){ //说明对象中已经存在cur这一项了,也说明cur在数组中重复了,我们需要把这一项删除
      // arr.splice(i,1) // 当前删除,后面每一项的索引都删除了,造成了数组塌陷现象,需要i--来修复,非常耗费性能
      // i--
      arr[i] = arr[arr.length -1] //把数组末尾那一项的值拿过来替换当前项
      arr.length-- //再把数组末尾那一项删除
      i--
      continue
    }
    obj[cur] = cur
  }

console.log(arr)

● 利用 indexOf实现数组去重

//不改变原数组
let arr = [1,2,3,4,5,1,2,3,4,5,6,2,3,4,1,42,42,52,34,3]

    function quchong(arr) {
      let newArr = []
        for(let i = 0; i < arr.length; i++){
          if(newArr.indexOf(arr[i]) == -1){ // 如果新数组没有这个数,就把这个数push进数组
            newArr.push(arr[i])
          }
        }
        return newArr //返回新数组
    }
    let newArr = quchong(arr);
    console.log(newArr)

递归

递归: 当前函数自己调用自己执行

//实现1-100之间,把所有不能被三整除的数相加
function sum(n) {
    //传递进来的值如果是0,说明已经累加到头了,我们不需要在调用自己继续累加了,返回一个0
    if(n === 0){
        return 0
    }
    // 如果传递进来的值可以被三整除的话,我们当前的值就不需要再累加了
    if(n % 3 === 0){
        return sum(n-1)
    }
    return n + sum(n - 1) // -> 100+sum(99) -> 100+99+sum(98) -> 100+99+98+sum(97).... -> 100+99+98+97+....+1+0
}

let total = sum(100)
console.log(total)


// 从1-10把所有能被二整除的进行相乘(递归)
function sum(n){
   
    if(n === 0){
        return 1   //最后返回一个1    防止变为0 和NaN
    }
    if(n % 2 !== 0){
       
        return sum(n-1)
    }
   
    return n * sum(n-1)
}

let total = sum(10)
console.log(total)

// =================================================================>
let count = 0
let timer = null
function move(){
    clearTimeout(timer)
    if(count >= 10) return
    count++ 
    console.log(count)
    //console.log(arguments.callee) //存储的是当前函数本身,等价于move
    // timer = setTimeout(arguments.callee,1000)
    timer = setTimeout(move,1000)

}
move()

冒泡排序

冒泡排序的思想: 让当前项和后一项进行比较,如果当前项大于后一项,两者交换位置

let arr = [4,3,5,2,1]

//第一轮
// 4>3 交换位置 [3,4,5,2,1]
// 4>5 不需要交换位置 [3,4,5,2,1]
// 5>2 交换位置 [3,4,2,5,1]
// 5>1 交换位置 [3,4,2,1,5]
// 第一次比对没有实现最后的目标,但是已经把数组中当前最大的那个值5放在数组的末尾位置了
// 第一轮比较四次  一共五个数,不用和自己比,最多比较四次

// 第二轮
// 3<4 不交换 [3,4,2,1,5]
// 4<2 交换 [3,2,4,1,5]
// 4<1 交换 [3,2,1,4,5]
// 也没有实现最后的目标,但是把剩余项目中最大的那个4放在倒数第二位了
// 第二轮比较三次 首先不用和自己比,最多四次,但是第一轮已经把最大的一个数放在末尾了,不需要和末尾比,所以只用比较三次


// 第三轮
// 3>2 交换 [2,3,1,4,5]
// 3>1 交换 [2,1,3,4,5]
// 第三轮比较两次,首先不用和自己比,最多四次,但是第一轮/第二轮已经把最大的两个数放在末尾了,不需要和末尾比,所以只用比较两次

// 第四轮
// 2>1 交换 [1,2,3,4,5]
// 第四轮比较一次 首先不用和自己比,最多四次,但是第一轮/第二轮/第三轮已经解决了三次,所以自己只需要比对一次就可以



// 每一轮当前项和后一项两两比较的话,虽然不一定达到最后的结果,但是已经把当前最大的那个值放在后面了
// 数组一共有五项,只需要比较四轮,把四个最大值分别的放在末尾,就实现了排序
// 一共最多比较多少轮:arr.length-1


// i 轮数 i = 0; i < arr.length - 1;
// j 每一次比较的次数
// i = 0 第一轮 j = 4 arr.length - 1 - 0  arr.length - 1 ->不用和自己比
// i = 1 第一轮 j = 3 arr.length - 1 - 1
// i = 2 第一轮 j = 2 arr.length - 1 - 2
// i = 3 第一轮 j = 1 arr.length - 1 - 3
// ...
// 每一轮比较的次数 arr.length - 1 - i
function bubbleSort(arr){

    for(let i = 0; i < arr.length - 1; i++){ // i 轮数
        let temp
        for(let j = 0 ; j < arr.length -1 -i; j++){ // j 每一轮比较的次数 -1 就是不用和自己比, -i 是上次比完的也不用比 
            if(arr[j] < arr[j+1]){
                temp = arr[j]
               arr[j] = arr[j+1]
               arr[j+1] = temp
    
            }
        }
    }
    return arr
}

console.log(bubbleSort(arr))

// 优化性能
function bubbleSort(arr){
    let flag = false  //判断是否已经排好序了
    for(let i = 0; i < arr.length - 1; i++){ // i 轮数
        let temp
        for(let j = 0 ; j < arr.length -1 -i; j++){ // j 每一轮比较的次数 -1 就是不用和自己比, -i 是上次比完的也不用比 
            if(arr[j] < arr[j+1]){
                temp = arr[j]
               arr[j] = arr[j+1]
               arr[j+1] = temp
                flag = true //本轮有交换就让flag = true
            }
        }
        if(flag){  //flag == true 上一轮有交换的,继续执行下一轮,并且让flag = false
            flag = false
        }else{  //上一轮没有交换 已经排好序了,直接结束循环
            break
        }
    }
    return arr
}

速排快序

/*
    快速排序的思想:
    1、我们首先在数组中找一个"基准点"(一般把基准点选择为数组中间的这一项)
    // Math.floor(arr.length/2) 例如:一共9项,获取的结果是4(第五项,正好是中间项);一共10项,获取的结果是5(第六项),也接近中间项
    2、拿基准点和数组中的其他项进行比较,比基准点小的放在左边,比基准点大的放在右边
    3、以后的每一遍都重复上述的两个操作,直到当前这一边只有一项的时候停止处理...
*/
    function quickSort(arr){
       
        if(arr.length <= 1) return arr  //如果传递过来的数组只有一项了,不需要再拆分排序了,直接把这个一项的数组返回即可
        let pointIndex = Math.floor(arr.length/2) //找到基准点的索引
        let pointValue = arr.splice(pointIndex,1)[0] //通过基准点的索引在原来的数组中,删除这一项,并把基准点的这一项的值获取到
        console.log(pointValue)

        //拿基准点的值和原来的数组中每一项进行比较,把小于基准点的放在左边,把大于基准点的放在右边
        let left = []
        let right = []
        for(let i = 0; i < arr.length; i++){
            let cur = arr[i]
            cur < pointValue ? left.push(cur) : right.push(cur)
        }
       return quickSort(left).concat([pointValue],quickSort(right))
    }



    let arr = [12,13,23,14,20,26,34,13,16,]
   const newArr = quickSort(arr)
   console.log(newArr)

插入排序

/**
 * 插入排序:
 * 把第一张牌放在左手
 * 以后拿到每一张牌的时候,和左手中的牌进行依次比较(一般来说我们的习惯是从后往前比较),如果当前的牌比倒数第一张小,再继续往左比...一直到遇到当前的牌一级比收敛的某张牌大了,则把这张牌插入到某张牌的后面(某张牌下一张牌的前面)
 * 
 */

function insertSort(arr) {
    // newArr 存储的就是我左手已经抓取的牌
    let newArr = []
    newArr[0] = arr[0] //先抓第一张牌

    //依次把桌面上第二张及以后的牌抓到
    for (let i = 0; i < arr.length; i++) {
        let cur = arr[i]
        //抓到当前牌之后,分别从后往前和左手中的牌进行比较
        for (let j = newArr.length - 1; j >= 0;) {
            if (cur < newArr[j]) { //当前新抓的牌比左手中的newArr[j]这张牌小,继续和newArr[j]前面的牌比
                j--
                if(j === -1){ //说明当前拿的这张牌比左手所有牌都小,把这张牌放在开头的位置即可
                   
                    newArr.unshift(cur);

                }
            } else { // 当前新抓的牌比左手中的newArr[j] 这张牌大,放在 newArr[j]这张牌的后面,也相当于插入到 newArr[j+1]这张牌的前面
                newArr.splice(j + 1, 0, cur)
                j = -1
            }
        }
    }

    return newArr
}

let arr = [2,3,5,6,7,3,4,1,98,12,4]

const newArr = insertSort(arr)
console.log(newArr)