冒泡排序算法

以下是一个基础的冒泡排序算法,实行的历程

  • 外部轮回len次

  • 内部轮回每次用arr[i]的值与arr[j]的值举行比较

  • 因为外部轮回的i变量每次进入内部轮回都不会转变,也就是arr[i]的值进入内部轮回后,都邑以本身与arr[j](也就是全部数组的一切元素)比较一轮,效果是小于arr[i]的数值都邑被放到数组的开首

  • 经由外层轮回的一次次的进入内层轮回的比对后,数组也遵照从小到大的顺序排列了

let arr = [1, 3, 2]
let len = arr.length

for(let i = 0; i < len; i++){
    for(let j = 0; j < len; j++){
        if(arr[i] > arr[j]){
            let temp = arr[i]
            arr[i] = arr[j]
            arr[j] = temp
        }
    }
}

我们来剖析步骤

第一轮外层轮回 i = 0
    第一轮内部轮回 
    j = 0
    
    arr[i] = 1 arr[j] = 1 arr[i] > arr[i]不建立,j++, arr坚持近况 [1, 3, 2]
    
    j = 1
    
    arr[i] = 1 arr[j] = 3 arr[i] > arr[j]不建立,j++, arr坚持原样 [1, 3, 2]
    
    j = 2
    
    arr[i] = 1 arr[j] = 2 arr[i] > arr[j]不建立,j++, arr坚持原样 [1, 3, 2]
    
    j = 3
    
    arr[i] = 1 arr[j] = undefined 因为len = 3 ,故 j < len不建立,第一轮层轮回完毕
第二轮外层轮回 i = 1
    第二轮内部轮回
    j = 0
    
    arr[i] = 3 arr[j] = 1 arr[i] > arr[i]建立, arr[i]和arr[j]交流数值,arr更新为[3, 1, 2]
    
    j = 1
    
    arr[i] = 1 arr[j] = 1 arr[i] > arr[i]不建立,j++, arr坚持原样 [3, 1, 2]
    
    j = 2
    
    arr[i] = 1 arr[j] = 2 arr[i] > arr[i]不建立,j++, arr坚持原样 [3, 1, 2]
    
    j = 3
    
    arr[i] = 1 arr[j] = undefined 因为len = 3 ,故 j < len不建立,第二轮层轮回完毕
第三轮外层轮回 i = 2
    第三轮内部轮回
    j = 0
    
    arr[i] = 2 arr[j] = 3 arr[i] > arr[i]不建立,j++, arr坚持原样 [3, 1, 2]
    
    j = 1
    
    arr[i] = 2 arr[j] = 1 arr[i] > arr[i]建立, arr[i]和arr[j]交流数值,arr更新为[3, 2, 1]
    
    j = 2
    
    arr[i] = 1 arr[j] = 1 arr[i] > arr[i]不建立,j++, arr坚持原样 [3, 2, 1
    
    j = 3
    
    因为尽人皆知的缘由,第三轮内部轮回完毕

第四轮外层轮回 i = 3

因为i < len不建立,外部轮回完毕,如今我们的数组终究效果为[3, 2, 1]

接下来我们来看看有没有优化的空间

我们发明,每次内部轮回都会从索引 let j = 0; 最先的,也就是说每次内部轮回 arr[j]
都邑把数组遍历一遍,因为在上一次的内部轮回完毕后,都邑把最大的数放到数组的头部,所以再次进入内部轮回时,假如还去重新比较就是浪费时间

所以怎样让内部轮回将上次列入最大值的位置疏忽呢?

答案就是i变量,每次完毕一次外部轮回i变量都邑加1,这也代表着有i个最大值被置于数组头部,也就是我们须要疏忽的位置,所以,我们只须要将内部轮回的肇端位置i加上i,就能够将已肯定的位置疏忽比较

for(let i = 0; i < len; i++){
    for(let j = 0 + i; j < len; i++){
        // 直接简写成let j = i也行
    }
}


然后我们来考证一下优化的效果

用一个大一点的数组,而且记录下轮回次数

let arr = [0,1,2,44,4,324,5,65,6,6,34,4,5,6,2,43,5,6,62,43,5,1,4,51,56,76,7,7,2,1,45,4,6,7]
let len = arr.length
let count = 0

for(let i = 0; i < len; i++){
  for(let j = 0; j < len; j++){
    count++
    if(arr[i] > arr[j]){
      let temp = arr[i]
      arr[i] = arr[j]
      arr[j] = temp
    }
  }
}

console.log(arr, count)
arr = [324, 76, 65, 62, 56, 51, 45, 44, 43, 43, 34, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 2, 2, 2, 1, 1, 1, 0]
count = 1156次

下面看下优化过的

let arr = [0,1,2,44,4,324,5,65,6,6,34,4,5,6,2,43,5,6,62,43,5,1,4,51,56,76,7,7,2,1,45,4,6,7]
let len = arr.length
let count = 0

for(let i = 0; i < len; i++){
  for(let j = i; j < len; j++){
    count++
    if(arr[i] > arr[j]){
      let temp = arr[i]
      arr[i] = arr[j]
      arr[j] = temp
    }
  }
}

console.log(arr, count)
arr = [0, 1, 1, 1, 2, 2, 2, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 34, 43, 43, 44, 45, 51, 56, 62, 65, 76, 324]
595次

效果毋庸置疑减少了近折半的无用轮回,那末到此为止了吗?
让我们再来看看
我们如今用的比较体式格局是基于用数组中的一个位置与一切位置举行比较,然后鄙人一轮比较时疏忽已肯定的位置,
以下:
[1, 3, 2]

1 比 1

1 比 3

1 比 2

人人是否是发明了一个无效操纵?就是1和1比较,这就是一个无效操纵,因为外部轮回的i和内部轮回的j初始化会相称,所以arr[i]和arr[j]会取到同一个位置的值比较一次,那末怎样优化这个操纵呢?

答案就是让内部j从第二位最先,防止和arr[i]取同一个值的状况

for(let i = 0; i < len; i++){
    for(let j = i; j < len - 1; j++){
       if(arr[i] > arr[j+1]){
           temp = arr[i];
           arr[i] = arr[j+1];
           arr[j+1] = temp;
       } 
    }
}

注重我给内部轮回的len减去了1,是因为给j+1的会致使末了一次arr[j+1]会溢出数组,所以将其减1,恰好弥补了j+1,也不会涌现少遍历数组元素的状况

然后我们来看看效果

[0, 1, 1, 1, 2, 2, 2, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 34, 43, 43, 44, 45, 51, 56, 62, 65, 76, 324]
561次
    原文作者:码码码畜
    原文地址: https://segmentfault.com/a/1190000009131092
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞