实现经典的9种排序算法,分析其时间复杂度以及空间复杂度,并用动画的方式演示。
常见的算法时间复杂度由小到大依次为:
Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n^2)<Ο(n^3)<…<Ο(2^n)<Ο(n!)
一、 直接插入排序
步骤:
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5
JavaScript实现:
var insertSort = function(arr){
for(let i=1;i<arr.length;i++){
let temp = arr[i];
for(var j=i-1;j>=0;j--){
if(arr[j] > temp){
arr[j+1] = arr[j];
arr[j] = temp;
}else{
break;//找到比temp小的则跳出循环
}
}
arr[j+1] = temp;//在比temp小的值后面插入temp值
}
return arr;
时间复杂度:
最好: O(n)
最坏: O(n^2)
平均: O(n^2)
动态图显示:
二、希尔排序
希尔排序,也叫递减增量排序,是插入排序的一种更高效的改进版本。希尔排序是不稳定的排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性
- 排序的效率但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位
JavaScript实现:
//希尔排序
var shellSort = function(arr,type,showSort){
var half = parseInt(arr.length/2);
for(let d=half;d>=1;d=parseInt(d/2) ){
for(let i=d;i<arr.length;i++){
for(let j=i-d;j>=0;j-=d){
if(arr[j+d] < arr[j]){
let tem = arr[j+d];
arr[j+d] = arr[j];
arr[j] = tem;
}
}
}
}
return arr;
}
时间复杂度:
最好: O(n*log2n)
最坏: O(n^2)
三、冒泡排序
步骤:
- 比较相邻的元素,如果前一个比后一个大,就把它们两个调换位置。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
JavaScript实现:
var bubbleSort = function(arr){
for(let i=1;i<arr.length;i++){
for(let j=0;j<arr.length-i;j++){
if(arr[j] > arr[j+1]){
let tem = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tem;
}
}
}
return arr;
}
时间复杂度:
最好: O(n)
最坏: O(n^2)
四、快速排序
步骤:
快速排序使用分治策略(Divide and Conquer)来把一个序列分为两个子序列,又称为分区交换排序。步骤为:
- 从序列中挑出一个元素,作为"轴值".
- 把所有比轴值小的元素放在轴值前面,所有比轴值大的元素放在轴值的后面,这个称为分区操作。
- 对每个分区递归地进行步骤1~2,递归的结束条件是序列的大小是0或1,这时整体已经被排好序了。
JavaScript实现:
//快速排序
var quickSort = function(arr,type,showSort){
//快速排序
var quick = function(out,first,end){
if(first<end){
let i=first, j=end, temp=0;
//一个循环完成一趟扫描
while(i<j){
while(i<j&& out[i]< out[j]){
j--;
}
if(i<j){
temp = out[i];
out[i] = out[j];
out[j] = temp;
i++;
}
while(i<j&& out[i] < out[j]){
i++;
}
if(i<j){
temp = out[i];
out[i] = out[j];
out[j] = temp;
j--;
}
}
quick(out,first,i-1);
quick(out,i+1,end);
}
return out;
}
return quick(arr,0,arr.length-1);
}
时间复杂度:
最好:O(n)
平均: O(n*log2n)
最坏: O(n^2)
五、选择排序
选择排序也是一种简单直观的排序算法。它的工作原理很容易理解:初始时在序列中找到最小(大)元素,放到序列的起始位置作为已排序序列;然后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
注意选择排序与冒泡排序的区别:冒泡排序通过依次交换相邻两个顺序不合法的元素位置,从而将当前最小(大)元素放到合适的位置;而选择排序每遍历一次都记住了当前最小(大)元素的位置,最后仅需一次交换操作即可将其放到合适的位置。
JavaScript实现:
//选择排序
var selectSort = function(arr,type,showSort){
for(let i=0;i<arr.length;i++){
let index = i;
for(let j=i;j<arr.length;j++){
if(arr[j] < arr[index]){
index = j;
}
}
let temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
}
return arr;
}
时间复杂度:
最好: O(n^2)