八大排序(完)

早就想总结下排序算法,一直没动手,这两天有时间就自己动手总结写写,暂时还没有区分内部排序或者外部排序,以及稳定性、时间复杂度、空间复杂度这些,看心情,想到哪个先写哪个。

1. 选择排序

i从0-max循环
每次都把(i+1)~ max中最小的值找出来,然后和i位置的元素进行交换

解:3, 5, 1, 2, 4, 7, 6

step 1:1 5  3  2  4  7  6

step 2:1  3  5  2  4  7  6 |  1  2 5  3  4  7  6 

step 3:1  2  3 5  4  7  6

step 4:1  2  3  4 5  7  6

step 5:1  2  3  4  5 7  6

step 6:1  5  3  2  4  6  7

function simpleSelectionSort(a) { //选择排序
        var tem;
        for(var i=0; i<a.length-1; i++) {
            for(var j=i+1; j<a.length; j++)
                if(a[j]<a[i]) {
                    tem = a[i];
                    a[i] = a[j];
                    a[j] = tem;
                }
        }
        return a;
    }


test:

var a = [3, 5, 1, 2, 4, 7, 6]
console.log(simpleSelectionSort(a))

2. 冒泡

bubble是算法和职业生涯中必不可少的,面试中9.9次会被问到,表示倒背如流,还有二分查找。

function bubbleSort(a) {
        var n = a.length;
        for(var i=0; i<n-1; i++) {
            for(var j=0; j<n-i-1; j++) {
                if(a[j+1]<a[j]) {
                    a[j] = [a[j+1],a[j+1]=a[j]][0]
                    //[a[j],a[i]] = [a[i],a[j]] #ie不支持
                }
            }
        }
        return a;
    }

test:

var a = [3, 5, 1, 2, 4, 7, 6]

console.log(bubbleSort(a))

3. 堆排序(其实就是二叉树)

用递归的办法,比如说深度为depth次,那么循环depth次:

1:比较左右孩子节点,如果左孩子>右孩子,则交换

2:比较此节点与左孩子节点,如果此节点>左孩子,则交换

3:重复1

这样的一个循环可以得出最小的节点的值,把这个节点存入新的数组a2,并把此节点从原有的数组中抛出,得出的新节点再去做上面的循环。

总共需要做a.length次。

以前上学时候学习算法,虽然努力学习,但是并不知道实际中到底怎么应用,直到去年要写个分类的列表,看起来很简单,就是父节点下有最多五个子节点,然后每个子节点又最多有五个子节点,然后列表深度最大为500。要做的操作是父节点选中,子节点全部选中,子节点有一个没有选中,那么父节点是没有选中的状态,子节点全部选中,那么父节点当然也是选中的状态,就这样往上层继续查找。作为一个大学期间学习过很长很长时间算法的人来说,我还是花了将近三天多时间来才写出了这个页面,比预期的两天延期了大半天。教训深重。。。and else。。。


代码如下:

function getLog(a, r) { //用于求得二叉树深度
        var i = 0;
        while(true) {
            if(Math.pow(a,i)==r)
                return i;
            else if(Math.pow(a,i)<r && Math.pow(a,i+1)>r)
                return i+1;
            else
                i++;
        }
    }

    function tarHeapSort(a) {
        var n = a.length;
        var left, right;
        var depth = getLog(2, n);
        var j = depth;
        while(--j>=0) {
            for(var i=0; i<n; i++) {
                left = i*2+1, right = i*2+2;
                if(right<n && a[left]>a[right]) {
                    [a[left], a[right]] = [a[right], a[left]];
                }
                if(left<n && a[left]<a[i]) {
                    [a[left], a[i]] = [a[i], a[left]]
                }
                if(right<n && a[left]>a[right]) {
                    [a[left], a[right]] = [a[right], a[left]];
                }
            }
        }
        return a;
    }

    function heapSort(a) {
        var n = a.length;
        var a2=[];
        var j = n;
        while(--j>=0) {
            a = tarHeapSort(a)
            a2.push(a[0])
            a.shift();
        }
        return a2;
    }


test:

var a = [10,9, 8, 7, 6, 5, 4, 3, 2, 1]
a = [2,1,3,4,5,2,1,4,10,3,-1,3]

console.log(heapSort(a))

4. 快速排序(分治、递归)

看过经典的快排算法,我自己写的时候另外定义了left和right数组,这样是又占用了空间,但是很好理解,个人觉得也是快排。

function quickSort(a) {
    var n = a.length;
    var soilder = a[n-1];
    var left=[], right=[soilder];
    var allIsEqual = 1;
    for(var i=0; i<n-1; i++) {
        if(a[i]<soilder) {
            left.push(a[i])
        } else {//right数组不可能为空,如果和soilder相等,都是放在right里
            right.push(a[i]);
            if(a[i]==soilder) {
                allIsEqual++;
            }
        }
        
    }
    if(allIsEqual==n) { //如果这个数组里面的额数字全部相等,就不用再比了
        return a;
    } else {
        if(left.length>1)
            left = quickSort(left);
        if(right.length>1)
            right = quickSort(right);
        return left.concat(right);
    }
}


test:

var a = [10,9, 8, 7, 6, 5, 4, 3, 2, 1]
    a = [2,1,3,4,5,2,1,3,-1,2,100,2,1,3,4,0]
    a = [1,2,1,2,3,1,1,1,1,1,1,1]

console.log(quickSort(a))

5. 基数排序(桶排序)

以前一直不理解基数排序,不能静下心去想,今天终于有心思看明白了,并把代码写了出来。支持多位数的数字。

基数排序就是先定义10个桶,编号0-9,然后把数组a中个位数等于桶的编号的数字放入对应桶中,最后按照桶的顺序把数字再重新放回数组a中。

然后清空桶,再把新的数组a中十位数字等于桶的编号的数字放入对应桶中,最后按照桶的顺序把数字再重新放回数组a中。

。。。

依次循环

在第一次循环的时候,遍历数组的同时会找到最大的数字位数。比方说是3(百位数),那么上面的循环进行三次。

代码如下:

//基数排序(桶排序)
function radixSort(a) {
    var n = a.length;
    var bucketCount = 10;
    var bucket = [], radix;
    var remainder = 1, maxDigit = 1;

    while(true) {
        bucket = [];
        for(var i=0; i<n; i++) {
            if(remainder==1 && getNoLength(a[i])>maxDigit) {
                maxDigit = getNoLength(a[i]);
            }
            radix = getNoDigit(a[i],remainder-1);
            if(typeof bucket[radix] == "object") {
                bucket[radix].push(a[i]);
            } else {
                bucket[radix] = [a[i]];
            }
        }
        a = []
        for(var i=0; i<10; i++) {
            if(typeof bucket[i] == "object") {
                a = a.concat(bucket[i])
            }

        }
        if(remainder==maxDigit) {
            break;
        } else {          
            remainder++;
        }
    }
    return a;
}
function getNoLength(n) {//获得数字的长度
    var s = n + "";
    return s.length;
}
function getNoDigit(n,i) {//获得数字n的倒数第i位,i从0开始
    var s = (n + "");
    s = s.split("").reverse();
    if(i>s.length-1) {
        return 0;
    } else {
        return s[i];
    }
}

6. 归并排序(又是递归、分治)

五一节后第一天,工作依然没什么事情,无奈,继续写排序,除此之外,不知道做什么了。。。

归并排序其实很简单,就是把一个数组先拆成有序数组,然后再合并有序数组。
function mergeSort(a) {
    var n = a.length;
    if(n<=1) {
        return a;
    } else if(n==2) {
        if(a[0]>a[1]) {
            [a[0], a[1]] = [a[1], a[0]]
        }
        return a;
    } else {
        var mid = Math.floor(n/2);
        var left = a.slice(0,mid), right = a.slice(mid);
        left = mergeSort(left);
        right = mergeSort(right);
        a = mergeArray(left, right);
        return a;
    }
}
function mergeArray(left, right) {//合并两个有序数组
    var a = [];
    var nl = left.length, nr = right.length;
    var i = 0, j = 0;
    while(i<nl&&j<nr) {
        if(left[i]<right[j]) {
            a.push(left[i++]);
        } else {
            a.push(right[j++]);
        }
    }
    a = a.concat(left.slice(i,nl));
    a = a.concat(right.slice(j,nr));
    return a;
}

test:

var a = [10,9, 8, 7, 6, 5, 4, 3, 2, 1]
//a = [2,1,3,4,5,2,1,3,-1,2,100,2,1,3,4,0]
//a = [1,5,2,3,4]
console.log(mergeSort(a))

7. 直接插入排序

直接插入排序应该是最简单的了,另设置一个数组长度为1的有序数组tem,tem[0]就是a[0],然后往里面顺序插入a[i]
function insertSort(a) {
    if(a.length<1) {
        return a;
    }
    var tem = [a[0]];
    for(var i=1; i<a.length; i++) {
        tem = insertToSortedArray(a[i], tem);
    }
    return tem;
}
function insertToSortedArray(n, a) {//把n插入有序数组a中
    var i;
    for(i=0; i<a.length; i++) {
        if(a[i]>n) {//插入a[i]前
            break;
        }
    }
    for(var j=a.length; j>i; j--) {
        a[j] = a[j-1];
    }
    a[i] = n;
    return a;

}


8. shell排序

function shellSort(a) {
    var gap = parseInt(a.length/2);
    while(gap>=1) {
        a = shellInsertSort(a, gap)
        gap = parseInt(gap/2);
    }
    return a;
}
function shellInsertSort(a, gap) {
    var j, tem;
    for(var i=gap; i<a.length; i++) {
        if(a[i]<a[i-gap]) {
            j = i-gap;
            tem = a[i];
            a[i] = a[j];
            while(tem<a[j]) {
                a[j+gap] = a[j];
                j -= gap;
            }
            a[j+gap] = tem;
        }
    }
    return a;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值