用js寫插入排序和選擇排序

我以爲做爲前端學學算法也是有益處的吧,因此今天就先來說講最基礎的排序算法。提高咱們程序員的內功~前端

插入排序

插入排序是n^2的基礎排序方法,大體思想是假設一個數組的前n個元素已經有序,而後考慮把第n+1個未排序的元素給插入到有序數組中去。現將n+1和第n個元素比較,若是n+1比n小,那麼就交換一下位置。以後咱們要排序的元素就在n這個位置上了,接着咱們繼續比較n和第n-1個元素的大小。如此反覆,直到咱們要插入的元素找到適合他的位置。
下面來示範一下
6--7--8--9--3--1--4--6--3--8--9--5
6--7--8--9已經有序,咱們要插入的元素是n=4這個元素3。比較9和3的大小,9比3大。交換一下位置
6--7--8--3--9,就變成了這個樣子。接着比較8和3的大小,8比3大,交換一下位置
6--7--3--8--9,繼續比較7和3的大小,7比3大,交換一下位置
6--3--7--8--9,繼續比較6和3的大小,6比3大,交換一下位置
3--6--7--8--9。到這裏循環結束,就已經排好序了。接着比較第n=5的元素1應該插入的位置,如此往復就把數組給排好了序了。
一下是代碼。程序員

//寫一個隨機生成數組的函數
function randomArr(count) {
  var arr = []
  for (var i = 0; i < count; i++) {
    var number = Math.ceil(Math.random() * 5000)
    arr.push(number)
  }
  return arr
}
// 交換元素位置的函數
function swap(arr, i, j) {
  var temp = arr[i]
  arr[i] = arr[j]
  arr[j] = temp
}

var arr = randomArr(5000)
// 插入排序函數
function insertionSort(arr) {
    var length = arr.length
    // 第0個元素默認就是有序的,由於只有一個元素,因此從第一個元素開始。arr[i]就是要插入的那個元素
    for (var i = 1; i < length; i++) {
        // 從第i-1個元素往前都是已經排好序的元素。因此最後一個開始往前比較
        for (var j = i - 1; j >= 0; j--) {
            // 這裏的j+1等於i這個元素。也就是arr[i] === arr[j+1]
            if (arr[j] > arr[j + 1]) {
                swap(arr, j + 1, j)
            } else {
                break
            }
        }
    }
    return arr
}
insertionSort(arr)

因爲是兩層for循環,因此它的時間複雜度是n^2級別的。
到這裏其實尚未完,插入排序仍是有能夠優化的地方的。如今的這個插入排序函數要swap頻繁的交換位置,咱們能夠這樣算法

function insertionSort(arr) {
    var length = arr.length
    // 第0個元素默認就是有序的,由於只有一個元素,因此從第一個元素開始。arr[i]就是要插入的那個元素
    for (var i = 1; i < length; i++) {
        // **用一個變量保存要插入的元素**
        var value = arr[i]
        // 從第i-1個元素往前都是已經排好序的元素。因此最後一個開始往前比較
        for (var j = i - 1; j >= 0; j--) {
            // 這裏的j+1等於i這個元素。也就是arr[i] === arr[j+1]
            if (arr[j] > value) {
                // 若是比要插入的元素大,把值arr[j]往右移一位
                arr[j+1] = arr[j]
                // 邊界條件,直到j等於0的時候終止循環,將value賦給arr[0],結束循環
                if (j === 0){arr[j] = value; break}
            } else {
                // 不然把value賦給arr[j]循環結束
                arr[j] = value
                break    
            }
        }
    }
    return arr
}

雖然插入排序是n^2級別的算法,可是在一個近乎有序的數組裏去實現插入排序,那麼他的效率會變的很是高。數組

由於插入排序能夠提早break掉內層循環。

有興趣能夠寫一個生成近乎有序數組的函數去實驗一下。dom

// 近乎有序數組
function nearlySorted(arr) {
  return arr
}

選擇排序

選擇排序就是在循環中不停的選擇最小的元素,而後交換位置。
下面來示範一下
6--7--8--9--3--1--4--6--3--8--9--5
找到數組中最小的元素1,而後記錄1的位置是5。接着交換位置變成
1--7--8--9--3--6--4--6--3--8--9--5
接着在剩下的數組裏7--8--9--3--6--4--6--3--8--9--5找到最小的元素3,記錄下它的下標位置是4,而後交換位置變成
1--3--8--9--7--6--4--6--3--8--9--5。如此往復直到排好序。函數

function randomArr(count) {
  var arr = []
  for (var i = 0; i < count; i++) {
    var number = Math.ceil(Math.random() * 5000)
    arr.push(number)
  }
  return arr
}
function swap(arr, i, j) {
  var temp = arr[i]
  arr[i] = arr[j]
  arr[j] = temp
}

var arr = randomArr(5000)

function selectionSort(arr) {
  var length = arr.length
  var value, pos
  for (var i = 0; i < length; i++) {
    value = arr[i]
    pos = i
    for (var j = i; j < length; j++) {
      var cur = arr[j]
      if (value > cur) {
        value = cur
        pos = j
      }
    }
    swap(arr, i, pos)
  }
  return arr
}
selectionSort(arr)

到此兩個基礎排序就實現了。總結一下,插入排序優於選擇排序。優化

插入排序能夠提早終止內層循環,若是數組近乎有序,那麼效率會很高。而選擇排序沒法提早終止循環。
不過最好的排序算法仍是nlogn級別的算法。如歸併排序和快速排序。
個人寫的不是最好的,僅僅是解釋概念,有興趣的同窗能夠本身寫一個更好的插入排序和選擇排序。code

相關文章
相關標籤/搜索