简单的排序算法整理(一)

简单的排序算法整理(一)

本文将介绍几个比较简单的排序算法,并基于JavaScript实现,全文分为一、二部分。

1.插入类排序

插入类排序的思想是:在一个已排好序的序列区内,对待排序的无序序列中的记录逐个进行处理,每一步都讲待排序的记录和已排好的序列中的记录进行比较,然后有序的插入到该序列中,直到所有待排序的记录全部插入为止。

(1)直接插入排序(基于顺序查找)

思想:每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。

第一趟比较前两个数,然后把第二个数按大小插入到有序表中;

第二趟把第三个数据与前两个数从后向前扫描,把第三个数按大小插入到有序表中;

依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。

效率:

时间复杂度:平均O(n^2),不适合对于数据量比较大的排序应用。

空间复杂度:O(1)

稳定性:稳定

js代码

 function sort(elements){
        for(var i = 1; i < elements.length; i++){
            if(elements[i] < elements[i-1]){
                var guard = elements[i];
                var j = i - 1;
                elements[i] = elements[j];
                while(j >= 0 && guard < elements[j]){
                    elements[j+1] = elements[j];
                    j--;
                }
                elements[j+1] = guard;
            }
        }
    }
(2)折半插入排序(基于折半查找)

思想:折半插入排序是对直接插入排序的简单改进,其过程是在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为a[low],末元素设置为a[high],则轮比较时将待插入元素与a[m],其中m=(low+high)/2相比较,如果比参考元素小,则选择a[low]到a[m-1]为新的插入区域(即high=m-1),否则选择a[m+1]到a[high]为新的插入区域(即low=m+1),如此直至low<=high不成立,即将此位置之后所有元素后移一位,并将新元素插入a[high+1]。

效率:

时间复杂度:平均O(n^2),折半查找只是减少了比较次数,但是元素的移动次数不变。

空间复杂度:附加空间O(1)

稳定性:稳定

js代码:

function pushArrayWithIndex(arr, index, value) { // 将元素添加到数组的指定位置
    var temArr = arr.slice(0, index);
    temArr.push(value);
    return temArr.concat(arr.slice(index));
}
function BiInsertSort(arr) { // 折半插入排序
    var temArr = []; // 临时数组,存储已排序项
    function getSortTmpIndex(subArr, num) {
        var len = subArr.length;
        if(0 == len) 
            return 0; // 当数组为空时,返回最开始位置
        var cpmIndex = Math.ceil(len / 2); // 计算中间元素所在位置
        if(cpmIndex > len - 1) 
            cpmIndex = len - 1;
        if(num == subArr[cpmIndex]) { // 相等时直接返回
            return cpmIndex;
        }
        if(num > subArr[cpmIndex]) { // 向后折半查找
            cpmIndex++;
            return cpmIndex + getSortTmpIndex(subArr.slice(cpmIndex), num);
        }
        if(num < subArr[cpmIndex]) { // 向前折半查找
            return getSortTmpIndex(subArr.slice(0, cpmIndex), num);
        }
    }
    for (var i in arr) {
        var index = getSortTmpIndex(temArr, arr[i]); //查找arr[i]在temArr中的位置
        temArr = pushArrayWithIndex(temArr, index, arr[i]); //将元素插入到查找位置
    }
    return temArr;
}
var arr = [3, 7, 6, 5, 9, 1, 2, 3, 1, 7, 4];
console.log("before:"+arr);
arr = BiInsertSort(arr);
console.log(" after:"+arr);
(3)希尔排序(基于逐趟缩小增量)

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

过程:

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。

所有距离为d1的倍数的记录放在同一个组中。

先在各组内进行直接插入排序;

然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量

dt=1(dt<dt-1…<d2<d1),

即所有记录放在同一组中进行直接插入排序为止。
效率:

时间复杂度:平均 O(n^2)
空间复杂度:需要辅助空间 O(1)

稳定性:不稳定

js代码:

    function ShellInsert(arr){
        var len=arr.length;
        for(var i=Math.floor(len/2);i>0;i=Math.floor(i/2)){
            for(var j=i;j<len;j++){
                for(var k=j-i;k>=0 && arr[k]>arr[i+k];k-=i){
                    var temp=arr[k];
                    arr[k]=arr[i+k];
                    arr[i+k]=temp;
                }
            }
        }
        return arr;
    }
    var arr=[49,38,65,97,76,13,27,49,55,04];
    console.log("before:"+arr);
    arr =ShellInsert(arr);
    console.log(" after:"+arr);

2.交换类排序

选择类排序的基本思想是:对待排序记录的关键字进行两两比较,只有发现两个记录为逆序就进行交换,直到没有逆序为止。

(1)冒泡排序

思想:

比较相邻的元素。如果第一个比第二个大,就交换他们两个。

对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

针对所有的元素重复以上的步骤,除了最后一个。

持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

效率:

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

空间复杂度:需要辅助空间 O(1)

稳定性:稳定

js代码:

    function bubbleSort(arr) {
        var i = arr.length, j;
        var tempExchangVal;
        while (i > 0) {
            for (j = 0; j < i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    tempExchangVal = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = tempExchangVal;
                }
            }
            i--;
        }
        return arr;
    }
    var arr = [3, 2, 4, 9, 1, 5, 7, 6, 8];
    console.log("before: "+arr);
    var arrSorted = bubbleSort(arr);
    console.log(" after: "+arrSorted);
(2)快速排序

思想:从待排序列中任意选择一个记录,以该记录的关键字作为“枢轴”,凡其关键字小于枢轴的记录均移至该记录之前,反之,凡是关键字大于枢轴的记录均移至该记录之后。

快速排序采用了分治策略,而分治法的基本思想是:将原问题分解为若干规模更小但是结构与原问题相似的子问题,递归的解决这些问题,然后将这些子问题的解组合为原问题的解。

效率:

时间复杂度:平均 O(Nlog*2*N)

空间复杂度:需要辅助空间 O(log*2*N)

稳定性:不稳定

js代码:

 function  quickSort (arr){
        if (arr.length <= 1) { return arr; }
            var pivotIndex = Math.floor(arr.length / 2);
            var pivot = arr.splice(pivotIndex, 1)[0];
            var left = [];
            var right = [];
            for (var i = 0; i < arr.length; i++){
                if (arr[i] < pivot) {
                    left.push(arr[i]);
                } else {
                    right.push(arr[i]);
                }
        }
        return quickSort(left).concat([pivot], quickSort(right));
    }
    var arr=[46,68,12,2,5,33,80,19,33];
    console.log("before: "+arr);
    var arr=quickSort (arr);
    console.log(" after: "+arr);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

英子的搬砖日志

您的鼓励是我创作的动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值