在知乎上看到这个题目,就自己写了一下,在这里附上链接,里面有各种排序的动态图,非常形象直观,有助于新手对排序算法理解,链接:常见排序算法之JavaScript实现
首先各种排序算法都会用到的交换函数:
function swap(Array,a,b){
var temp;
temp=Array[a];
Array[a]=Array[b];
Array[b]=temp;
}
冒泡排序:
function bubbleSort(array){
var len=array.length;
var i,j;
var temp;
//注意只用执行n-1次排序,因为第n次排序,最小的那个数已经归位了
for(i=0;i<len-1;i++){
for(j=0;j<len-i-1;j++){
if(array[j]>array[j+1]){
swap(array,j,j+1);
}
}
}
return array;
}
冒泡排序有两层循环,时间复杂度大概是o(n*n),而且移动次数很多,每次循环都要移动o(n)的次数,感觉还是很伤的,数比较少的时候用比较好。
选择排序:
function selectionSort(array){
var len=array.length;
var i,j;
var min;//记录最小的那个下标
for(i=0;i<len-1;i++){
min=i;
for(j=i+1;j<len;j++){
if(array[j]<array[min])
min=j;
}
swap(array,i,min);
}
return array;
}
有两处和知乎不同,1、我的是len-1层循环,知乎上是len层,我应该是对的,因为最后一个数已经是最大了。2、知乎里写了这个判断,我当时写的时候没想到,加上:
if(i!=min){
swap(array,i,min);
}
选择排序相比冒泡排序节省了不少移动的次数,每次循环只移动了一次,但也是两层循环,每次循环要从头到尾比较一下,时间复杂度也是O(n*n)
插入排序:
function insertionSort(array){
var len=array.length;
var i,j,k;
for(i=1;i<len;i++){
if(array[i]<array[0])
backward(array,0,i);
for(j=i-1;j>0;j--){
if(array[i]<array[j]&&array[i]>array[j-1])
backward(array,j,i);
}
}
return array;
}
function backward(Array,a,b){
var i;
var temp=Array[b];
for(i=b;i>a;i--)
Array[i]=Array[i-1];
Array[a]=temp;
}
知乎上的代码比我的简短,区别:1、我增加了一个判断,如果插入的元素比第一个小就直接移动,不用一个一个比较了。2、我写了一个backward()函数移动元素,知乎上的是比较一次移动一次,那个代码逻辑比较清晰,但是我这个效率上面应该会好一点,毕竟不用多次读写。
插入排序的移动次数和冒泡排序差不多,时间复杂度应该也是O(n*n)
归并排序:
已经不想多说什么,这个排序我想了最久,代码:
function merge(array,i){
var newArray=new Array();
for(var j=0;j<=array.length;j=j+i){ newArray=newArray.concat(insertionSort(array.slice(j,j+i)));
}
return newArray;
}
function mergeSort(array){
var i=2;
while(i<=array.length){
var result=merge(array,i);
i=i*2;
}
if(i>array.length)
for(var j=0;j<array.length;j++){
insertionSort(array);
}
return array;
}
用slice()方法取得数组的一部分,需要注意的是该方法并不会改变数组,而是返回一个新的子数组,splice()方法会对原数组进行操作。
知乎上的方法比较好,分成左右两个数组,然后再进行递归,我一开始也想用这个方法,后来在分界上搞不定,发现知乎的做法也没有拘泥于分界,比如是这样[1,44,5]->[1],[44,5]而我总想[1,44],[5],其实不用拘泥于这个,做出来就行。然后在两个数组进行合并的时候,知乎是用了两个指针,分别指向两个数组,边比较边移动,我是直接调用了前面写的插入排序。总的来说被知乎写法完爆。。
快速排序:
算法功底差,想的脑仁疼,代码如下:
function fastSort(array,a,b){
var i,j,p;
p=a;
j=p+1;
for(i=j;i<=b;i++){
if(array[i]<array[p]){
if(i!=j)
swap(array,i,j);
j++;
}
}
swap(array,p,j-1);
if(a<j-1)
fastSort(array,a,j-1);
if(j<b)
fastSort(array,j,b);
return array;
}
和知乎上代码差别挺大的,我是取第一个数为基准值,然后在原数组上进行的操作,知乎上面是取中间为基准值,然后建两个数组,left和right,比基准小的放在left,比基准大的放在right,然后把left和基准和right连接起来,为什么感觉别人的代码逻辑都很清楚。。。
备注:concat()方法用于连接两个或者多个数组,用法为arrayA.concat(arrayB,arrayC,…)。