冒泡排序
冒泡排序算法的原理如下:
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 ----摘自百度百科
function bubbleSort(array) {
//时间复杂度为O(n^2),稳定,空间复杂度O(1)
let length = array.length
for (let i = 0; i < length; i++) {
for (let j = 0; j < length - 1; j++) {
if (array[j] > array[j + 1]) {
;[array[j], array[j + 1]] = [array[j + 1], array[j]]
}
}
}
}
bubbleSort(array)
选择排序
原理:
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法 ----摘自百度百科
function selectSort(array) {
//时间复杂度为O(n^2),不稳定,空间复杂度O(1)
let min,
minIndex,
length = array.length
// debugger
for (let i = 0; i < length; i++) {
min = array[i]
minIndex = i
for (let j = i + 1; j < length; j++) {
if (min > array[j]) {
min = array[j]
minIndex = j
}
}
if (minIndex !== i) {
;[array[minIndex], array[i]] = [array[i], array[minIndex]]
}
}
}
selectSort(array)
插入排序
原理:
通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到{\displaystyle O(1)}的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。 ----摘自维基百科
function insertSort(array) {
//时间复杂度为O(n^2),稳定,空间复杂度O(1)
let j = 0,
i = 0,
temp = 0,
length = array.length
// debugger
for (i = 1; i < length; i++) {
if (array[i - 1] > array[i]) {
j = i
temp = array[i]
while (j > 0 && temp < array[j - 1]) {
array[j] = array[j - 1]
j--
}
array[j] = temp
}
}
}
insertSort(array)
快速排序
原理:
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。
步骤为:
- 从数列中挑出一个元素,称为"基准"(pivot),
- 重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任何一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归到最底部时,数列的大小是零或一,也就是已经排序好了。这个算法一定会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。 ----摘自维基百科
function quickSort(arr, left, right) {
//时间复杂度为O(nlogn);平均时间复杂度:O(nlogn),最坏事件复杂度O(n^2)。稳定性:不稳定的。辅助空间:O(nlogn)
if (left >= right) {
return
}
let flag = arr[left],
i = left,
j = right
// debugger
while (true) {
while (arr[j] >= flag && j !== i) {
j--
}
while (arr[i] <= flag && i !== j) {
i++
}
;[arr[i], arr[j]] = [arr[j], arr[i]]
if (i === j) {
break
}
}
;[arr[left], arr[j]] = [arr[j], arr[left]]
// console.log(arr)
quickSort(arr, left, j)
quickSort(arr, j + 1, right)
}
quickSort(array, 0, array.length - 1)
希尔排序
原理:
希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,知道区域划分值为一,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快) ----摘自维基百科
function shellSort(arr) {
let length = arr.length
//gap表示分成几组
//最坏时间复杂度为O(n^2);最优时间复杂度为O(n);平均时间复杂度为O(n^(3/2)),空间复杂度O(1)
for (let gap = ~~(length / 2); gap > 0; gap = ~~(gap / 2)) {
for (let i = gap; i < length; i++) {
for (var j = i - gap; j >= 0 && arr[j] > arr[gap + j]; j -= gap) {
;[arr[j], arr[j + gap]] = [arr[j + gap], arr[j]]
}
}
}
}
shellSort(array)
归并排序
原理:
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
- 重复步骤3直到某一指针到达序列尾
- 将另一序列剩下的所有元素直接复制到合并序列尾 ----摘自维基百科
//空间复杂度为:O(n) 最差、最优、平均时间复杂度都为O(nlogn) 稳定
function mergeSort(arr) {
if (arr.length === 1) {
return arr
}
let middle = arr.length >> 1,
leftArr = arr.slice(0, middle),
rightArr = arr.slice(middle)
return merge(mergeSort(leftArr), mergeSort(rightArr))
}
function merge(leftArr, rightArr) {
let temp = []
while (leftArr.length > 0 && rightArr.length > 0) {
if (leftArr[0] < rightArr[0]) {
temp.push(leftArr.shift())
} else {
temp.push(rightArr.shift())
}
}
return temp.concat(leftArr, rightArr)
}
array = mergeSort(array)