排序算法之插入排序

6 篇文章 0 订阅
3 篇文章 0 订阅
学过的东西总是容易忘记阿,想要再重头建起来也不是那么容易的一件事。温故而知新,嘿嘿!

今天就把插入排序算法理清。

顾名思义,插入,那首先得要有一个能够插的对象——这就是已经排好了序的一个序列。生活中这种事很常见,比如斗地主,如果是一张牌一张牌地拿在手上的话,普通人的大小王永远是放在两端(这取决于每个人的排序习惯)。
排序算法之插入排序

如上图所示,这时候你拿起了一张7,左手上的牌是排好序的,现在你就要帮这个7选择一个合适的位置。这就是插入排序的思想。

再举一个例子,体育课第一节课一般都是要先从高到矮先站位。然后来了一个迟到的学生,这时候就要帮这个学生寻找一个合适的位置,让他也能参与到课堂上来。总不能就一直让他在一边干瞪着吧。哈哈!生活中这些例子都应用到了插入排序算法。

不讲那么多废话,直接上插入排序JS代码

function insert_sort(arr){
    var len = arr.length;
    for (var i = 1; i < len; i++){
        if (arr[i] < arr[i - 1]){      //发生逆序,往前插入
            var temp = arr[i];
            var j;
            for (j = i - 1;j>=0 && arr[j]>temp; j--){
                arr[j+1] = arr[j];
            }
            arr[j+1] = temp;
        }
    }
    return arr;
}
var startTime = new Date();
var result = insert_sort([2,4,1,3,8,7,4,0,6,10]);
console.log(result);
var endTime = new Date();
console.log(endTime-startTime);

插入排序比较厉害,他的子孙后代在自己的基础上发展出了更多性能改进的算法,比如折半插入排序(二分插入排序)这个“儿子”。他想到“爸爸”这么一个个的对比,真是迟钝又浪费时间,所以他跳跃着对比。省去了很多时间。
折半插入排序JS代码

function insert_binary_sort(arr) {          // 插入排序
    var temArr = [];                // 临时数组,存储已排序项
    function getSortTmpIndex(subArr, num) {
        var len = subArr.length;
        if(0 == len) return 0; // 当数组为空时,返回最开始位置
            var mid = Math.ceil(len / 2); // 计算中间元素所在位置
        if(mid > len - 1) {
            mid = len - 1;
        }
        if(num == subArr[mid]) { // 相等时直接返回
            return mid;
        }
        if(num > subArr[mid]) { // 向后折半查找
            mid++;
            return mid + getSortTmpIndex(subArr.slice(mid), num);
        }
        if(num < subArr[mid]) { // 向前折半查找
            return getSortTmpIndex(subArr.slice(0, mid), num);
        }
    }
    for (var i in arr) {
        var index = getSortTmpIndex(temArr, arr[i]); // 查找arr[i]在temArr中的位置
        console.log('index:', index, ' num:', arr[i], ' arr:', temArr);
        temArr.splice(index, 0 , arr[i]); // 将元素插入到查找位置
    }
    return temArr;
}
var startTime = new Date();
var result = insert_binary_sort([2,4,1,3,8,7,4,0,6,10]);
console.log(result);
var endTime = new Date();
console.log(endTime-startTime);

另外一个“儿子”——希尔排序。这个智商爆表的二儿子,让人很难以理解他是怎么想出来这么处理问题。大家就看图体会一下吧。排序过程图如下:
排序算法之插入排序
希尔排序JS代码:

function shell_sort(arr){
    len=arr.length;
    for(var fraction = Math.floor(len/2) ; fraction>0 ; fraction = Math.floor(fraction/2)){
        for(var i = fraction ; i < len ; i++){
            for(var j = i - fraction ; j >= 0 && arr[j] > arr[ fraction + j ] ; j -= fraction){
                var temp = arr[j];
                arr[j] = arr[fraction+j];
                arr[fraction+j] = temp;
            }
        }
    }
    return arr;
}
var startTime = new Date();
var result = shell_sort([2,4,1,3,8,7,4,0,6,10]);
console.log(result);
var endTime = new Date();
console.log(endTime-startTime);

说了三个排序算法,但是不知道什么情况应该使用它们,也就只是纸上谈兵。大家会觉得程哥没诚意,现在就给大家分享一下。

性能问题: 如果目标是把n个元素的序列升序排列,那么采用插入排序存在 最好情况 最坏情况 。最好情况就是,序列已经是升序排列了,在这种情况下,需要进行的比较操作需(n-1)次即可。最坏情况就是,序列是降序排列,那么此时需要进行的比较共有n(n-1)/2次。插入排序的赋值操作是比较操作的次数加上 (n-1)次。平均来说插入排序算法的时间复杂度为O(n^2)。因而,插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,例如, 量级小于千 ,那么插入排序还是一个不错的选择。

稳定性: 插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,就是第一个元素。比较是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。

由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以希尔排序是不稳定的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值