left.push(arr[i]);
}else{
right.push(arr[i]);
}
}
returnquickSort(left).concat([pivot],quickSort(right));
};
六、堆排序
1)算法简介
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。
堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:
即子结点的键值或索引总是小于(或者大于)它的父节点。
2)算法描述和实现
具体算法描述如下:
将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无序区;
将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n];
由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。
不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
JavaScript代码实现:
/*方法说明:
堆排序
@paramarray待排序数组*/
functionheapSort(array){
if(Object.prototype.toString.call(array).slice(8,-1)==='Array'){
//建堆
varheapSize=array.length,temp;
for(vari=Math.floor(heapSize/2);i>=0;i--){
heapify(array,i,heapSize);
}
//堆排序
for(varj=heapSize-1;j>=1;j--){
temp=array[0];
array[0]=array[j];
array[j]=temp;
heapify(array,0,--heapSize);
}
}else{
return'arrayisnotanArray!
';
}
}
/*方法说明:
维护堆的性质
@paramarr数组
@paramx数组下标
@paramlen堆大小*/
functionheapify(arr,x,len){
if(Object.prototype.toString.call(arr).slice(8,-1)==='Array'&&typeofx==='number'){
varl=2*x,r=2*x+1,largest=x,temp;
if(larr[largest]){
largest=l;
}
if(rarr[largest]){
largest=r;
}
if(largest!
=x){
temp=arr[x];
arr[x]=arr[largest];
arr[largest]=temp;
heapify(arr,largest,len);
}
}else{
return'arrisnotanArrayorxisnotanumber!
';
}
}
3)算法分析
最佳情况:
T(n)=O(nlogn)
最差情况:
T(n)=O(nlogn)
平均情况:
T(n)=O(nlogn)
七、归并排序
1)算法简介
归并排序是建立在归并操作上的一种有效的排序算法。
该算法是采用分治法(DivideandConquer)的一个非常典型的应用。
归并排序是一种稳定的排序方法。
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
若将两个有序表合并成一个有序表,称为2-路归并。
2)算法描述和实现
具体算法描述如下:
把长度为n的输入序列分成两个长度为n/2的子序列;
对这两个子序列分别采用归并排序;
将两个排序好的子序列合并成一个最终的排序序列。
JavaScript代码实现:
functionmergeSort(array,p,r){
if(pvarq=Math.floor((p+r)/2);
mergeSort(array,p,q);
mergeSort(array,q+1,r);
merge(array,p,q,r);
}
}
functionmerge(array,p,q,r){
varn1=q-p+1,n2=r-q,left=[],right=[],m=n=0;
for(vari=0;ileft[i]=array[p+i];
}
for(varj=0;jright[j]=array[q+1+j];
}
left[n1]=right[n2]=Number.MAX_VALUE;
for(vark=p;k<=r;k++){
if(left[m]<=right[n]){
array[k]=left[m];
m++;
}else{
array[k]=right[n];
n++;
}
}
}
3)算法分析
最佳情况:
T(n)=O(n)
最差情况:
T(n)=O(nlogn)
平均情况:
T(n)=O(nlogn)
八、桶排序
1)算法简介
桶排序(Bucketsort)的工作的原理:
假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。
2)算法描述和实现
具体算法描述如下:
设置一个定量的数组当作空桶;
遍历输入数据,并且把数据一个一个放到对应的桶里去;
对每个不是空的桶进行排序;
从不是空的桶里把排好序的数据拼接起来。
JavaScript代码实现:
/*方法说明:
桶排序
@paramarray数组
@paramnum桶的数量*/
functionbucketSort(array,num){
if(array.length<=1){
returnarray;
}
varlen=array.length,buckets=[],result=[],min=max=array[0],regex='/^[1-9]+[0-9]*$/',space,n=0;
num=num||((num>1&®ex.test(num))?
num:
10);
for(vari=1;imin=min<=array[i]?
min:
array[i];
max=max>=array[i]?
max:
array[i];
}
space=(max-min+1)/num;
for(varj=0;jvarindex=Math.floor((array[j]-min)/space);
if(buckets[index]){//非空桶,插入排序
vark=buckets[index].length-1;
while(k>=0&&buckets[index][k]>array[j]){
buckets[index][k+1]=buckets[index][k];
k--;
}
buckets[index][k+1]=array[j];
}else{//空桶,初始化
buckets[index]=[];
buckets[index].push(array[j]);
}
}
while(nresult=result.concat(buckets[n]);
n++;
}
returnresult;
}
3)算法分析
桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。
很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。
但相应的空间消耗就会增大。
九、计数排序
1)算法简介
计数排序(Countingsort)是一种稳定的排序算法。
计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素的个数。
然后根据数组C来将A中的元素排到正确的位置。
它只能对整数进行排序。
2)算法描述和实现
具体算法描述如下:
找出待排序的数组中最大和最小的元素;
统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
反向填充目标数组:
将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。
JavaScript代码实现:
functioncountingSort(array){
varlen=array.length,B=[],C=[],min=max=array[0];
for(vari=0;imin=min<=array[i]?
min:
array[i];
max=max>=array[i]?
max:
array[i];
C[array[i]]=C[array[i]]?
C[array[i]]+1:
1;
}
for(varj=min;jC[j+1]=(C[j+1]||0)+(C[j]||0);
}
for(vark=len-1;k>=0;k--){
B[C[array[k]]-1]=array[k];
C[array[k]]--;
}
returnB;
}
3)算法分析
当输入的元素是n个0到k之间的整数时,它的运行时间是O(n+k)。
计数排序不是比较排序,排序的速度快于任何比较排序算法。
由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。