前言 学习排序算法是大一下学期上数据结构课的时候的事了,当时学习用的是c++
,如今javascript
已经成了我的主语言。为了准备面试和巩固基础,我决定用js写一遍10大排序算法并且上传到博客,算是复习一遍基础的算法吧。
冒泡排序(Bubble Sort) 算法描述
使用冒泡排序为一列数字进行排序的动态效果图
冒泡排序 (英语:Bubble Sort )又称为泡式排序 ,是一种简单的排序算法 。它重复地走访过要排序的数列 ,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
算法实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let bubble_sort = (array ) => { let length = array.length for (let i = 0 ; i<length-1 ; i++) { for (let j = 0 ; j<length-1 -i; j++) { if (array[j]>array[j+1 ]) { [array[j], array[j+1 ]] = [array[j+1 ], array[j]] } } } console .log(array) return array }let num = [22 , 34 , 3 , 32 , 82 , 55 , 89 , 50 , 37 , 5 , 64 , 35 , 9 , 70 ]; bubble_sort(num)
一个冒泡排序的例子动画
名字
最好时间复杂度
最坏时间复杂度
平均时间复杂度
空间复杂度
是否稳定
冒泡排序
n
n²
n²
1
是
[^是否稳定]: 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面; 不稳定 :如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面
选择排序(Selection Sort) 算法描述
动态效果图
选择排序 (Selection sort)是一种简单直观的排序算法 。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
选择排序的主要优点与数据移动有关。如果某个元素位于正确的最终位置上,则它不会被移动。选择排序每次交换一对元素,它们当中至少有一个将被移到其最终位置上,因此对n个元素的表进行排序总共进行至多n-1次交换。在所有的完全依靠交换去移动元素的排序方法中,选择排序属于非常好的一种。
算法实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 let selection_sort = (array ) => { let length = array.length let minIndex for (let i = 0 ; i<length-1 ; i++) { minIndex = i for (let j = i+1 ; j<length; j++) { if (array[j]<array[minIndex]) { minIndex = j } } [array[i], array[minIndex]] = [array[minIndex], array[i]] } console .log(array) return array } selection_sort([22 , 34 , 3 , 32 , 82 , 55 , 89 , 50 , 37 , 5 , 64 , 35 , 9 , 70 ])
名字
最好时间复杂度
最坏时间复杂度
平均时间复杂度
空间复杂度
是否稳定
选择排序
n²
n²
n²
1
否
插入排序(Insertion Sort) 算法描述
动态效果
插入排序 (英语:Insertion Sort)是一种简单直观的排序算法 。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序 在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
算法实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 let insertion_sort = (array ) => { let length = array.length for (let i=1 ; i<length; i++) { console .log(array[i]) let key = array[i] let j = i-1 while (j>=0 && array[j]>key) { array[j+1 ] = array[j] j-- } array[j+1 ] = key } console .log(array) return array } insertion_sort([22 , 34 , 3 , 32 , 82 , 55 , 89 , 50 , 37 , 5 , 64 , 35 , 9 , 70 ])
名字
最好时间复杂度
最坏时间复杂度
平均时间复杂度
空间复杂度
是否稳定
插入排序
n
n²
n²
1
是
希尔排序(Shell Sort) 算法介绍 希尔排序 (Shellsort),也称递减增量排序算法 ,是插入排序 的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序 的效率
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位
算法描述
算法实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 let shell_sort = (array ) => { for (let gap = array.length>>1 ; gap>0 ; gap>>=1 ) { for (let i = gap; i<array.length; i++) { let temp = array[i],j for (j = i-gap; j>=0 && array[j]>temp; j-=gap) { array[j+gap] = array[j] } array[j+gap] = temp } } console .log(array) return array } shell_sort([22 , 34 , 3 , 32 , 82 , 55 , 89 , 50 , 37 , 5 , 64 , 35 , 9 , 70 ])
名字
最好时间复杂度
最坏时间复杂度
平均时间复杂度
空间复杂度
是否稳定
希尔排序
nlog(n)
n (log(n))2
无法确定
1
否
归并排序 算法介绍
动态效果
归并排序 (英语:Merge sort,或mergesort),是创建在归并操作上的一种有效的排序算法 ,效率 为{\displaystyle O(n\log n)(大O符号 )。1945年由约翰·冯·诺伊曼 首次提出。该算法是采用分治法 (Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。
算法描述
把长度为n的输入序列分成两个长度为n/2的子序列
对这两个子序列分别采用归并排序
将两个排序好的子序列合并成一个最终的排序序列
算法实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 let merge_sort = (array ) => { if (array.length<2 ) { return array } let middle = Math .floor(array.length/2 ) let left = array.slice(0 , middle) let right = array.slice(middle) return merge(merge_sort(left), merge_sort(right)) }let merge = (left, right ) => { let res = [] while (left.length>0 && right.length>0 ) { if (left[0 ]<right[0 ]) { res.push(left.shift()) } else { res.push(right.shift()) } } return res.concat(left, right) }console .log(merge_sort([22 , 34 , 3 , 32 , 82 , 55 , 89 , 50 , 37 , 5 , 64 , 35 , 9 , 70 ]))
名字
最好时间复杂度
最坏时间复杂度
平均时间复杂度
空间复杂度
是否稳定
归并排序
nlog(n)
nlog(n)
nlog(n)
n
是
快速排序 算法介绍 快速排序 (英语:Quicksort),又称分区交换排序 (partition-exchange sort),简称快排 ,一种排序算法 ,最早由东尼·霍尔 提出。在平均状况下,排序n个项目需要O(nlog(n))次比较。在最坏状况下则需要O(n²)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地达成。
算法实现 首先实现数组的分区代码函数,partition
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let partition = (array, start, end ) => { let pivotIndex = 0 let pivotValue = array[end] for (let i=0 ; i<end; i++) { if (array[i]<pivotValue) { [array[i], array[pivotIndex]] = [array[pivotIndex], array[i]] pivotIndex++ } } [array[end], array[pivotIndex]] = [array[pivotIndex], array[end]] return pivotIndex }
在排序的函数中用递归来把大问题划分成若干个小问题,只要这个函数收到一个不为空或有多个元素的数组,则将重复该过程
1 2 3 4 5 6 7 8 9 10 11 12 let quick_sort = (array, start, end ) => { if (start>=end) { return } let index = partition(array, start, end) quick_sort(array, start, index-1 ) quick_sort(array, index+1 , end) return array }console .log(quick_sort([22 , 34 , 3 , 32 , 82 , 55 , 89 , 50 , 37 , 5 , 64 , 35 , 9 , 70 ],0 ,13 ))
名字
最好时间复杂度
最坏时间复杂度
平均时间复杂度
空间复杂度
是否稳定
快速排序
nlog(n)
n²
nlog(n)
log(n)
否
参考资料
十大经典排序算法总结(JavaScript描述)
javascript-algorithms