冒泡排序算法

以下是一個基本的冒泡排序算法,執行的過程算法

  • 外部循環len次數組

  • 內部循環每次用arr[i]的值與arr[j]的值進行比較優化

  • 因爲外部循環的i變量每次進入內部循環都不會改變,也就是arr[i]的值進入內部循環後,都會以自身與arr[j](也就是整個數組的全部元素)比較一輪,結果是小於arr[i]的數值都會被放到數組的開頭code

  • 通過外層循環的一次次的進入內層循環的比對後,數組也依照從小到大的順序排列了排序

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]
都會把數組遍歷一遍,因爲在上一次的內部循環結束後,都會把最大的數放到數組的頭部,因此再次進入內部循環時,若是還去從頭比較就是浪費時間console

因此如何讓內部循環將上次列入最大值的位置忽略呢?變量

答案就是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次
相關文章
相關標籤/搜索