七大排序算法

目录:[top]

前言

使用语言javascript;尽量使用改进的算法;默认从小到大排序;代码均经过实践;
排序基本概念:
1,内排序,在内存中排序。外排序,数量太大,需要借助外存。
2,排序稳定性,相同的数字应该在排序之后仍然不变(如已经按照学号
排好之后再需要按成绩排名,要求排名之后学号仍然是有序的。这样
情况下需要排序稳定)
3,性能指标,时间复杂度和空间复杂度。


冒泡排序

时间复杂度
 O(n*(n-1)/2)   =>   O(n^2)   稳定
思想
每轮相邻交换最后,最大的被换到了最后
优缺点
时间复杂度大,只适合小的数组
关键代码
function BubbleSort(a){
    //从前往后冒,取最大的
    //外层循环0-a.length-1次
    for(var i=0;i< a.length-1;i++){
        //内层循环0-a.length-i+1次
        for(var j=0;j<=a.length-i-1;j++){
            if(a[j]>a[j+1]){
                change(a[j],a[j+1]);
            }
        }
    }
    return a;
}

选择排序

时间复杂度
  O(n*(n+1)/2)  =>   O(n^2)    不稳定
思想
  依次选择无序区的最小值加入有序区
优缺点
易理解,时间代价大。适合小数组
关键代码
function selectSort(a){
    var i;
    for(i=0;i<a.length-1;i++){
        var min=a[i];
        for(var j=i;j<a.length;j++){
            if(a[j]<min) min=a[j];
        }
        var res=a.indexOf(min);
        change(a[res],a[i]);
    }
    return a;
}

插入排序

时间复杂度
O((n+4)*(n-1)/2)  =>  O(n^2)   稳定
思想
依次将无序区值插入有序区中.优化:折半插入排序.
优缺点
相对于前面两种,比较次数得到明显减少。但是对于数组的操作移动
比较麻烦。
关键代码
function insertSort(arr){
    for(var i=1;i<arr.length;i++){
        //[0,i-1]是有序区,[i,arr.length]是无序区
        var now=arr[i];//当前需要被插入的数字
        for(var j=0;j<i;j++){
            if(arr[j]>now){
                if(j==0) arr.unshift(now);
                else  arr.splice(j-1,0,now);
                break;
            }
        }
    }
    return arr;
}

希尔排序

时间复杂度
O(n^2)~O(nlog2N)  不稳定
思想
预先根据数组的大小设置一组步数数组,最后一步必须是1.直到原分组数组
只有一个数的时候停止,此时原数组为有序的了。
关键是步数的设置。一般的说法是设置这个数组长度的1/2依次这样。例如
数组大小为10,则设置步数序列为[5,3,2,1].
优缺点
只适合小规模数组。这个步数序列难以设置。
关键代码
function shellSort(a){
    var step=[5,3,1];
    for(var i=0;i<step.length;i++){
        for(var j=0;j+step[i]< a.length;j++){
            var max=j+step[i];
            if(a[j]>a[max]){
                //change(a[j],a[max]);
                var temp;
                temp=a[j];
                a[j]=a[max];
                a[max]=temp;
            }
        }
    }
    return a.toString();
}

归并排序

时间复杂度
O(nlog2N)      稳定
思想
归并排序--分治法--将无序序列分为n个单个的序列.再依次两两合并成
组内有序,组外无序。
到了需要递归的函数的时候,先进行递归,直至递归结束.然后开始回溯,从
最"新"的递归结果开始回溯,一次执行下面的程序.因此,递归的处理类似于
栈---先进后处理。
首先寻找递归结束的条件,递归之后的函数执行是从内向外执行的!---栈
优缺点
思想较复杂。时间复杂度仍然太大。
关键代码
function mergeSort(a){
    var len= a.length;
    if(len<2) return a;//递归结束的条件时的处理
        var center=Math.floor(len/2);//平分
    return merge(mergeSort(a.slice(0,center)),
    mergeSort(a.slice(center+1)));
    //左数组和有数组进行合并。递归的思想,从内部向外部
}
function merge(leftArr,rightArr){
    var final=[];
    while(leftArr.length || rightArr.length){
        final.push(leftArr[0]<=rightArr[0] ? 
        leftArr.shift() : rightArr.shift());
    }
    return final.concat(leftArr.concat(rightArr));
}

快速排序

时间复杂度
O(nlog2N)  不稳定
空间复杂度:需要一个栈,栈深:O(log2N)
思想
从无序区选取一个记录设置为k,左边都存放比K小的,右边都存放比k大的。
依次循环,直到数组里只有一个值。让将所有的值进行拼接。此时借助递归
的思想。
优缺点
不稳定排序,时间非常短。
关键代码
    function quick_sort(arr) {
    var len = arr.length;
    if (len <= 1)
        return arr.slice(0);//数组只有一个值。取出字串0开始
    var left = [];//左字串
    var right = [];//右字串
    var key = [arr[0]];//被比较的数组,为每个数组的第一个数字
    for (var i = 1; i < len; i++) {
        if (arr[i] < key[0])   left.push(arr[i]);
        //小于key值放在左边
        else   right.push(arr[i]);
    }
    //最后把左右半部执行递归的的排序结果拼接
    return quick_sort(left).concat(key.concat(quick_sort(right)));
}

堆排序

时间复杂度
建堆:O(nlog2N) 维护堆:O(log2N)   =>O(nlog2N)   不稳定
思想
首先将待排序列构造小根堆,选取堆顶元素为最小值,并将其移走(或将堆
顶记录和最后一个元素进行交换)。将剩余的记录维护成为一个堆,这样再
取顶部最小值。直到堆中只有一个元素。
关键:1,从(0-n/2-1)为非叶子节点(即,一定有左子树。因下标需要从0开始)
2,若右子树不存在(2*i+1>n),结束维护堆
3,若右子树存在(2*i+1<=n)选取左右子树最大的和跟比较(即,a[2i+1<2i+2] MaxSon++)
4,与跟比较a[MaxSon]>a[i]则将这个最大的和跟交换,并且再次维护堆。
优缺点
对原始排序的记录并不敏感。适合与大量的数据。
关键代码
Array.prototype.heap_sort = function() {
    var arr = this.slice(0);
    function swap(i, j) {
        var tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    function max_heapify(start, end) {
        var dad = start;//父节点
        var son = dad * 2 + 1;//子节点
        if (son >= end)//无右子树
            return;
        if (son + 1 < end && arr[son] < arr[son + 1])
        //选取左右子树最大的
            son++;
        if (arr[dad] <= arr[son]) {
        //父节点小于最大子节点
        //交换父子,并且再次维护堆
            swap(dad, son);
            max_heapify(son, end);
        }
    }

    var len = arr.length;
    //只对非叶子节点进行   父子维护
    for (var i = Math.floor(len / 2) - 1; i >= 0; i--)
        max_heapify(i, len);
    //依次取出每个大根堆的根节点
    for (var i = len - 1; i > 0; i--) {
        swap(0, i);
        max_heapify(0, i);
    }

    return arr;
};

总结

主要是掌握算法的思想!及其优缺点和优化方式。

具体代码可以前往我的git下载 https://github.com/zyd317/algorithm-sort

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值