前端面试之排序算法

几种排序算法的比较

排序算法最差时间复杂度平均时间复杂度空间复杂度稳定度
冒泡排序O(n2)O(n2)O(1)稳定
直接插入排序O(n2)O(n2)O(1)稳定
归并排序O(nlog2n)O(nlog2n)O(n)稳定
简单选择排序O(n2)O(n2)O(1)不稳定
希尔排序O(n2)O(n*log2n)O(1)不稳定
堆排序O(n*logn)O(n*logn)O(1)不稳定
快速排序O(n2)O(n*log2n)O(logn)~O(n)不稳定

冒泡排序

最坏时间复杂度:O(n^2)

空间复杂度:O(1)

稳定性:稳定

第一种方法:

原理:对数组进行遍历,相邻元素根据大小进行交换,每次遍历将最小值推至最前方,然后对剩下的值再次进行比较

Array.prototype.sort = function() {
    var len = this.length,
    i, j, k, tmp;
    for(i=0;i<len;i++) {
        for(j=len-1;j>i;j--) {          //每轮冒泡将最小的数移到前面
            if(this[j] < this[j-1]) {
                tmp = this[j] ;
                this[j] = this[j-1] ;
                this[j-1] = tmp ;
            }
        }
    }
}

var array = [5,4,6,7,8] ;
array.sort() ;
console.log(array) ;

第二种方法:

  1. 比较相邻的前后二个数据,如果前面数据大于后面的数据,就将二个数据交换。
  2. 这样对数组的第0个数据到N-1个数据进行一次遍历后,最大的一个数据就“沉”到数组第N-1个位置。
  3. N=N-1,如果N不为0就重复前面二步,否则排序完成。
Array.prototype.sort = function() {
    var len = this.length,
    i, j, k, tmp;
    for(i=0;i<len;i++) {
        for(j=1;j<len-i;j++) {          //每轮冒泡将最大的数移到后面
            if(this[j] < this[j-1]) {
                tmp = this[j] ;
                this[j] = this[j-1] ;
                this[j-1] = tmp ;
            }
        }
    }
}

var array = [5,4,6,7,8] ;
array.sort() ;
console.log(array) ;

优化

如果有100个数的数组,仅前面10个无序,后面90个都已排好序且都大于前面10个数字,那么在第一趟遍历后,最后发生交换的位置必定小于10,且这个位置之后的数据必定已经有序了,记录下这位置,第二次只要从数组头部遍历到这个位置就可以了。

Array.prototype.sort = function() {
    var len = this.length,
    flag = len,         //用于记录最后一次交换的位置
    j, k, tmp;
    while(flag > 0) {
        k = flag ;
        flag = 0 ;
        for(j=1;j<k;j++) {
            if(this[j-1] > this[j]) {
                tmp = this[j-1] ;
                this[j-1] = this[j] ;
                this[j] = tmp ;
                flag = j ;
            }
        }
    }
}

var array = [5,4,6,7,8,9,10,11,12,13,14,15,16,17,18,19] ;
array.sort() ;
console.log(array) ;

参考链接

插入排序

最坏时间复杂度:O(n^2)

平均时间复杂度:O(n^2)

空间复杂度:O(1)

稳定性:稳定

原理:从数组第二个值开始,依次将后续的数值经过比较与前面排序后的序列比较后插入。

方法一:
Array.prototype.sort = function() {
    var len = this.length,
        i, j, tmp ; 
    for(i=1;i<len;i++) {
        tmp = this[i] ;
        j = i - 1 ;
        while(j>=0 && this[j] > tmp) {
            this[j+1] = this[j] ;
            j-- ;
        }
        this[j+1] = tmp ;
    }
}

var array = [5,17,4,16,6,18,12,8,9,11,14,7,15,10,13,19] ;
array.sort() ;
console.log(array) ;
方法二:
Array.prototype.sort = function() {
    var len = this.length,
        i, j, tmp ; 
    for(i=1;i<len;i++) {
        for(j=i-1;j>=0&&this[j]>this[j+1];j--) {
            tmp = this[j] ;
            this[j] = this[j+1] ;
            this[j+1] = tmp ;
        }
    }
}

var array = [5,17,4,16,6,18,12,8,9,11,14,7,15,10,13,19] ;
array.sort() ;
console.log(array) ;

参考链接

归并排序

最坏时间复杂度:O(nlogn)

平均时间复杂度:O(nlogn)

空间复杂度:O(n)

稳定性:稳定

基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,那么就可以很方便的将这二组数据进行排序。

参考链接

选择排序

最坏时间复杂度:O(n^2)

平均时间复杂度:O(n^2)

空间复杂度:O(1)

稳定性:不稳定

原理:与冒泡排序类似,只不过选择排序不是通过相邻元素交换而将最小值“冒泡”到顶端,而是从数组第一个元素开始,与后面的的元素进行比较,如果后面的元素都比他大,则不需要交换,如果有比其小的,则两个值相互交换。

Array.prototype.sort = function() {
    var len = this.length,
        i, j, k, tmp ; 
    for(i=0;i<len;i++) {
        k = i ;
        for(j=i+1;j<len;j++) {
            if(array[j] < array[k]) {
                k = j ;
            }
        }

        if(k != i) {
            tmp = this[i] ;
            this[i] = this[k] ;
            this[k] = tmp ;
        }
    }
}

var array = [5,17,4,16,6,18,12,8,9,11,14,7,15,10,13,19] ;
array.sort() ;
console.log(array) ;

参考链接

希尔排序

最坏时间复杂度:O(n^2)

平均时间复杂度:O(nlogn)

空间复杂度:O(1)

稳定性:不稳定

基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。

Array.prototype.sort = function() {
    var len = this.length,
    i, j, tmp, gap ; 
    for(gap=len/2;gap>0;gap/=2) {
        for(i=gap;i<len;i++) {
            for(j=i-gap;j>=0&&this[j]>this[j+gap];j-=gap) {
                tmp = this[j+gap] ;
                this[j+gap] = this[j] ;
                this[j] = tmp ;
            }
        }
    }
}

var array = [5,17,4,16,6,18,12,8,9,11,14,7,15,10,13,19] ;
array.sort() ;
console.log(array) ;

参考链接1
参考链接2

堆排序

最坏时间复杂度:O(n*logn)

平均时间复杂度:O(n*logn)

空间复杂度:O(1)

稳定性:不稳定

首先可以看到堆建好之后堆中第0个数据是堆中最小的数据。取出这个数据再执行下堆的删除操作。这样堆中第0个数据又是堆中最小的数据,重复上述步骤直至堆中只有一个数据时就直接取出这个数据。

由于堆也是用数组模拟的,故堆化数组后,第一次将A[0]与A[n - 1]交换,再对A[0…n-2]重新恢复堆。第二次将A[0]与A[n – 2]交换,再对A[0…n - 3]重新恢复堆,重复这样的操作直到A[0]与A[1]交换。由于每次都是将最小的数据并入到后面的有序区间,故操作完成后整个数组就有序了。

注意使用最小堆排序后是递减数组,要得到递增数组,可以使用最大堆。

参考链接

快速排序

最坏时间复杂度:O(n^2)

平均时间复杂度:O(n*logn)

空间复杂度:O(logn)~O(n)

稳定性:不稳定

该方法的基本思想是:
  1. 先从数列中取出一个数作为基准数。
  2. 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
  3. 再对左右区间重复第二步,直到各区间只有一个数。

举例

function quicksort(array,left,right) {
    if(left < right) {
        var i = left,
        j = right,
        x = array[left] ;
        while(i < j) {
            while(i<j && array[j]>=x) {
                j-- ;
            }
            if(i<j){
                array[i++] = array[j] ;
            }
            while(i<j && array[i]<x) {
                i++;
            }
            if(i<j) {
                array[j--] = array[i] ;
            }
        }
        array[i] = x ;
        quicksort(array,left,i-1) ;
        quicksort(array,i+1,right) ;
    }
}

var array = [72,6,57,88,60,42,83,73,88,85,60] ;
quicksort(array,0,10) ;
console.log(array) ;

参考链接

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值