JavaScript實現冒泡排序法、插入排序法、快速排序法

1.冒泡排序法

1.1 概念

冒泡排序(Bubble Sort),是一種計算機科學領域的較簡單的排序算法。

它重複地走訪過要排序的元素列,依次比較兩個相鄰的元素,如果順序(如從大到小、首字母從Z到A)錯誤就把他們交換過來。走訪元素的工作是重複地進行直到沒有相鄰元素需要交換,也就是說該元素列已經排序完成。

這個算法的名字由來是因爲越小的元素會經由交換慢慢“浮”到數列的頂端(升序或降序排列),就如同碳酸飲料中二氧化碳的氣泡最終會上浮到頂端一樣,故名“冒泡排序”。

1.2 原理示意圖

冒泡排序
流程圖1

1.3 代碼
const arr = [5, 2, 7, 8, 34, 7, 39, 12, 56, 9, 1]

  function bubbleSort(arr) {
    const len = arr.length
    // 外層循環i控制比較的輪數
    for (let i = 0; i < len; i++) {
      // 裏層循環控制每一輪比較的次數j,arr[i] 只用跟其餘的len - i個元素比較
      for (let j = 1; j < len - i; j++) {
        // 若前一個元素"大於"後一個元素,則兩者交換位置
        if (arr[j - 1] > arr[j]) {
          [arr[j - 1], arr[j]] = [arr[j], arr[j - 1]]
        }
      }
    }
    return arr
  }

  console.log(bubbleSort(arr))	// [1, 2,  5,  7,  7, 8, 9, 12, 34, 39, 56]
  

改進的冒泡排序法:

function bubbleSort(arr) {
    let temp = null, flag = 1
    const len = arr.length
    for (let i = 0; i <= len - 1 && flag === 1; i++) {
      flag = 0
      for (let j = 0; j < len - i; j++) {
        if (arr[j] > arr[j + 1]) {
          temp = arr[j + 1]
          arr[j + 1] = arr[j]
          arr[j] = temp
          flag = 1// 發生數據交換flag置爲1
        }
      }
    }
    return arr
  }

2.插入排序法

2.1 概念

一般也被稱爲直接插入排序(Insert Sort)。對於少量元素的排序,它是一個有效的算法。插入排序是一種最簡單的排序方法,它的基本思想是將一個記錄插入到已經排好序的有序表中,從而一個新的、記錄數增1的有序表。在其實現過程使用雙層循環,外層循環對除了第一個元素之外的所有元素,內層循環對當前元素前面有序表進行待插入位置查找,並進行移動。

插入排序是指在待排序的元素中,假設前面n-1(其中n>=2)個數已經是排好順序的,現將第n個數插到前面已經排好的序列中,然後找到合適自己的位置,使得插入第n個數的這個序列也是排好順序的。按照此法對所有元素進行插入,直到整個序列排爲有序的過程,稱爲插入排序。

2.2 原理示意圖

插入排序
插入排序的工作方式像許多人排序一手撲克牌。開始時,我們的左手爲空並且桌子上的牌面向下。然後,我們每次從桌子上拿走一張牌並將它插入左手中正確的位置。爲了找到一張牌的正確位置,我們從右到左將它與已在手中的每張牌進行比較。拿在左手上的牌總是排序好的,原來這些牌是桌子上牌堆中頂部的牌 。
插入排序

2.3 代碼
function quickSort(arr) {
  // 4.結束遞歸(當ary小於等於一項,則不用處理)
  if (arr.length <= 1) {
    return arr
  }
  // 1. 找到數組的中間項,在原有的數組中把它移除
  const middleIndex = Math.floor(arr.length / 2)
  const middle = arr.splice(middleIndex, 1)[0]
  // 2. 準備左右兩個數組,循環剩下數組中的每一項,比當前項小的放到左邊數組中,反之放到右邊數組中
  const leftArr = [], rightArr = []
  for (let i = 0; i < arr.length; i++) {
    const current = arr[i]
    current < middle ? leftArr.push(current) : rightArr.push(current)

  }
  // 3. 遞歸方式讓左右兩邊的數組持續這樣處理,一直到左右兩邊都排好序爲止。
  //(最後讓左邊+中間+右邊拼接成最後的結果)
  return quickSort(leftArr).concat(middle, quickSort(rightArr))
}

另一種解法:

  const arr = [5, 2, 7, 8, 34, 7, 39, 12, 56, 9, 1]

  function insertSort(arr) {
    const handle = [arr[0]], len = arr.length
    for (let i = 1; i <= len - 1; i++) {
      const current = arr[i]
      for (var j = handle.length - 1; j >= 0; j--) {
        if (current > handle[j]) {
          handle.splice(j + 1, 0, current)
          break
        }
        if (j === 0) {
          handle.unshift(current)
        }
      }
    }
    return handle
  }

  console.log(insertSort(arr))	// [1, 2,  5,  7,  7, 8, 9, 12, 34, 39, 56]
  

優化的插入排序法:
優化的插入排序

	//將arr[]按升序排列,插入排序法
  function insertSort(arr) {
    for (let i = 1; i < arr.length; i++) {
      //將arr[i]插入到arr[i-1],arr[i-2],arr[i-3]……之中
      for (let j = i; j > 0; j--) {
        if (arr[j] < arr[j - 1]) {
          [arr[j - 1], arr[j]] = [arr[j], arr[j - 1]]
        }
      }
    }
    return arr
  }

3.快速排序法

3.1 概念

快速排序(Quick Sort)是對冒泡排序的一種改進。

快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。

3.2 原理示意圖快速排序快速排序##### 3.3 代碼
function quickSort(arr) {
  // 4.結束遞歸(當ary小於等於一項,則不用處理)
  if (arr.length <= 1) {
    return arr
  }
  // 1. 找到數組的中間項,在原有的數組中把它移除
  const middleIndex = Math.floor(arr.length / 2)
  const middle = arr.splice(middleIndex, 1)[0]
  // 2. 準備左右兩個數組,循環剩下數組中的每一項,比當前項小的放到左邊數組中,反之放到右邊數組中
  const leftArr = [], rightArr = []
  for (let i = 0; i < arr.length; i++) {
    const current = arr[i]
    current < middle ? leftArr.push(current) : rightArr.push(current)

  }
  // 3. 遞歸方式讓左右兩邊的數組持續這樣處理,一直到左右兩邊都排好序爲止。
  //(最後讓左邊+中間+右邊拼接成最後的結果)
  return quickSort(leftArr).concat(middle, quickSort(rightArr))
}

另一種寫法:

  const arr = [5, 2, 7, 8, 34, 7, 39, 12, 56, 9, 1]

  function quickSort(outter) {
    function sort(arr, left = 0, right = arr.length - 1) {
      if (left >= right) {    //如果左邊的索引大於等於右邊的索引說明整理完畢
        return
      }
      let i = left, j = right
      const baseVal = arr[j]  // 取無序數組最後一個數爲基準值
      while (i < j) {         //把所有比基準值小的數放在左邊大的數放在右邊
        while (i < j && arr[i] <= baseVal) { //找到一個比基準值大的數交換
          i++
        }
        arr[j] = arr[i] // 將較大的值放在右邊如果沒有比基準值大的數就是將自己賦值給自己(i 等於 j)
        while (j > i && arr[j] >= baseVal) {  //找到一個比基準值小的數交換
          j--
        }
        arr[i] = arr[j] // 將較小的值放在左邊如果沒有找到比基準值小的數就是將自己賦值給自己(i 等於 j)

      }
      arr[j] = baseVal        // 將基準值放至中央位置完成一次循環(這時候 j 等於 i )
      sort(arr, left, j - 1)  // 將左邊的無序數組重複上面的操作
      sort(arr, j + 1, right) // 將右邊的無序數組重複上面的操作
    }

    const newArr = outter.concat()// 爲了保證這個函數是純函數拷貝一次數組
    sort(newArr)
    return newArr
  }

  console.log(bubbleSort(arr))	// [1, 2,  5,  7,  7, 8, 9, 12, 34, 39, 56]
  

4.十大排序空間複雜度和時間複雜度:

十大排序

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章