Javascript罕見排序算法的筆記

  排序算法重要針對的是數組,所以,在最先進修之前,我們先本身新建一種數據結構來輕易我們的進修。

function ArrayData () {
  let ret = []
  this.times = 0  // 統計實行次數
  this.push = (item) => {
    ret.push(item)
  }
  this.toString = () => {
    return ret.join()
  }
}

const arr = [34, 11, 45, 22, 31, 99, 68, 54]

冒泡排序

  比較相鄰兩個數的大小,假如前面的數大於背面,則交流這兩個數的位置。要排序n個数字,須要閱歷n-1次的遍歷。

  根據字面請求,我們寫出來的代碼是如許的

function ArrayData () {
    // ......
    this.bubbleSort = function () {
        let length = ret.length;
        for (let i = 0; i < length; i++) {
          for (let j = 0; j < length - 1; j++) {
            this.times++
            if (ret[j] > ret[j + 1]) {
              [ret[j], ret[j + 1]] = [ret[j + 1], ret[j]]
            }
          }
        }
    }
}

let tmp = new ArrayData()
arr.forEach((item) => {
    tmp.push(item)
})
tmp.bubbleSort()
console.log(tmp.times)    //  56

  明顯這類簡樸粗獷的排序體式格局有很大的提拔空間,比方,我們能夠檢測每次排序,假如遞次已分列勝利,就沒必要實行以後的輪迴了。

function ArrayData () {
    // ......
    this.bubbleSort = function () {
        let length = ret.length;
        for (let i = 0; i < length; i++) {
          let change = false
          for (let j = 0; j < length - 1; j++) {
            this.times++Ï
            if (ret[j] > ret[j + 1]) {
              [ret[j], ret[j + 1]] = [ret[j + 1], ret[j]]
              change = true
            }
          }
          if (!change) {
            break
          }
        }
    }
}

let tmp = new ArrayData()
arr.forEach((item) => {
    tmp.push(item)
})
tmp.bubbleSort()
console.log(tmp.times)    //  21

  實在照樣有優化的空間的。舉個例子,假定一共8個數,第一輪輪迴,會把最大的數冒泡排到第8位,第二輪輪迴,會把第二大的數排到第7位,所以,本輪循壞實在沒必要斟酌末了一名了。同理,下一輪輪迴就不須要斟酌后兩位。革新后的代碼以下:

function ArrayData () {
    // ......
    this.bubbleSort = function () {
        let length = ret.length;
        for (let i = 0; i < length; i++) {
          let change = false
          for (let j = 0; j < length - 1 - i; j++) {
            this.times++
            if (ret[j] > ret[j + 1]) {
              [ret[j], ret[j + 1]] = [ret[j + 1], ret[j]]
              change = true
            }
          }
          if (!change) {
            break
          }
        }
    }
}

let tmp = new ArrayData()
arr.forEach((item) => {
    tmp.push(item)
})
tmp.bubbleSort()
console.log(tmp.times)    //  18

挑選排序

  遍曆數組,找出最小的數排在第一名,第二輪輪迴找出第二小的數放在第二位,以此類推。

function ArrayData () {
    // ......
  this.selectionSort = function () {
    let length = ret.length
    for (let i = 0; i < length - 1; i++) {
      let minIndex = i
      for (let j = i; j < length; j++) {
        if (ret[j] < ret[minIndex]) {
          minIndex = j
        }
      }
      if (i !== minIndex) {
        [ret[i], ret[minIndex]] = [ret[minIndex], ret[i]]
      }
    }
  }
}

let tmp = new ArrayData()
arr.forEach((item) => {
    tmp.push(item)
})
tmp.selectionSort()

插進去排序

  把數組分紅前後兩部份,前面的一部份是排好序的,然後分別把背面一部份的数字插進去到前面排好序的數組中。所以,剛最先時設定第一個元素為排好序的部份,分別把背面的数字插進去進來。

function ArrayData () {
    // ......
  this.insertSort = function () {
    let length = ret.length
    let j
    for (let i = 1; i < length; i++) {
      let currentNumber = ret[i]
      for (j = i - 1; j >= 0 && ret[j] > currentNumber; j--) {
        ret[j + 1] = ret[j] 
      }
      ret[j + 1] = currentNumber 
    }
  }
}

let tmp = new ArrayData()
arr.forEach((item) => {
    tmp.push(item)
})
tmp.insertSort()

疾速排序

  選一個數作為基準數,遍曆數列,把比它
放到他前面,比他小的放到他背面,然後再對基準數前後的數列遞歸上述操縱,直到數列長度為1。

function ArrayData () {
    // ......
    this.quickSort = function () {
        quick(ret, 0, ret.length - 1);
    
        function quick(array, left, right) {
          let index
          if (array.length > 1) {
            index = partition(array, left, right)
            if (left < index - 1) {
              quick(array, left, index - 1)
            }
            if (right > index) {
              quick(array, index, right)
            }
          }
          return array
        }
    
        function partition(array, left, right) {
          let pivot = array[Math.floor((right + left) / 2)],
            i = left,
            j = right;
          while (i <= j) {
            while (array[i] < pivot) {
              i++
            }
            while (array[j] > pivot) {
              j--
            }
            if (i <= j) {
              swap(array, i, j);
              i++;
              j--;
            }
          }
          return i
        }
    
        function swap(array, i, j) {
          [array[i], array[j]] = [array[j], array[i]]
        }
    }
}

let tmp = new ArrayData()
arr.forEach((item) => {
  tmp.push(item)
})
tmp.quickSort()

  一句話完成疾速排序。挑選第一個元素作為參考元素,應用filter把數組分紅大於參考元素和小於參考元素的兩個數組,並對這兩個數組遞歸挪用快排函數。

function quickSort(arr) {
  return arr.length <= 1 ? arr : quickSort(arr.slice(1).filter((item) => item <= arr[0])).concat(arr[0], quickSort(arr.slice(1).filter((item) => item > arr[0])))
}

希爾排序

  希爾排序是把數組按下標的肯定增量分組,對每組舉行插進去排,跟着增量逐步削減,每一個數組的長度越來越多,當增量減至1時,全部文件恰被分紅一組,算法便停止。

function ArrayData () {
    // ......
  this.shellSort = function () {
    let length = ret.length
    for (let step = Math.floor(length / 2); step > 0; step = Math.floor(step / 2)) {
      for (let i = 0; i < step; i++) {
        shellInsertSort(i, step)
      }
    }

    function shellInsertSort(index, step) {
      let length = ret.length
      let j
      for (let i = index; i < length; i += step) {
        let currentNumber = ret[i]
        for (j = i - step; j >= 0 && ret[j] > currentNumber; j -= step) {
          ret[j + step] = ret[j]
        }
        ret[j + step] = currentNumber
      }
    }
  }
}

let tmp = new ArrayData()
arr.forEach((item) => {
  tmp.push(item)
})
tmp.shellSort()

兼并排序

  兼并排序採納分治的頭腦,將已有序的子序列兼并,獲得完整有序的序列。所以我們把數列分割成不凌駕兩個元素的數組,然後將其兼并。

function ArrayData () {
    // ......
  this.mergeSort = function () {
    ret = mergeSortFun(ret)

    function mergeSortFun(arr) {
      let length = arr.length
      if (length <= 1) {
        return arr
      }
      let mid = Math.floor(length / 2),
        left = arr.slice(0, mid),
        right = arr.slice(mid, length)
      return mengeConnect(mergeSortFun(left), mergeSortFun(right))
    }

    function mengeConnect(left, right) {
      let
        leftIndex = 0,
        rightIndex = 0,
        result = []
      while (leftIndex < left.length && rightIndex < right.length) {
        result.push(left[leftIndex] < right[rightIndex] ? left[leftIndex++] : right[rightIndex++])
      }
      while (leftIndex < left.length) {
        result.push(left[leftIndex++])
      }
      while (rightIndex < right.length) {
        result.push(right[rightIndex++])
      }
      return result
    }
  }
}

let tmp = new ArrayData()
arr.forEach((item) => {
  tmp.push(item)
})
tmp.mergeSort()
    原文作者:志如
    原文地址: https://segmentfault.com/a/1190000015347051
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞