重温一下 数组排序的算法

本次重温了四个算法:冒泡排序,希尔排序,插入排序,快速排序

首先创建一个公共的方法,交换两个数字在数组中的位置

function swap(array, index_1, index_2) {
    let a = array[index_1];

    array[index_1] = array[index_2];
    array[index_2] = a;
    return array;
}
  • 冒泡排序
var arr = [2,3,4,5,1,23,0,6,9,8,7];
/**
 - 循环遍历,将每一个值与后面的值进行对比,如果后面的值比当前值小,就交换位置,从而达到冒泡排序
 - 每次需要循环 n-1, n-2, n-3, n-4, ..., 1, 一共n次
 - 所以是 (n-1 + 1)*n / 2 =》 n^2/2舍去常数,也就是n^2
 **/
Array.prototype.bubbling = function() {
    for(let i = 0; i < this.length; i++) {
        for(let j = i + 1; j < this.length; j++) {
            let current = this[i];
            let compare = this[j];
            if(compare < current) {
                swap(this, i, j);
            }
        }
    }
    return this;
}
  • 希尔排序

     希尔排序,是基于冒泡之上的,理念差不多,只不过从之前的每一个都要和后面的所有项对比改为,间隔着对比。 在一定程度上可以减少运算量。
    

    例如

  • 有数组 7 5 9 3 1 2 4,长度的一半向下取整为3,也就是说当前数字与 当前数字索引值+3的数字进行对比
    1) 7 > 3 => 3 5 9 7 1 2 4
    2) 5 > 1 => 3 1 9 7 5 2 4
    3) 9 > 2 => 3 1 2 7 5 9 4
    4) 7 > 4 => 3 1 2 4 5 9 7
    这时4+3>length-1(6),所以本次循环结束

  • 上次的间隔为3,第二次是 3/2 向下取整 为1,数组为 3 1 2 4 5 9 7 ***
    1)3 > 1 => 1 3 2 4 5 9 7
    2) 3 > 2 => 1 2 3 4 5 9 7
    3) 3 < 4
    4) 4 < 5
    5) 5 < 9
    6) 9 > 7 => 1 2 3 4 5 7 9

这样下来,总共用了10次,如果用冒泡的话,需要 6+5+4+3+2+1,21次,少了11次

在我这个基础上有一个小改动,可以使这个数组的排序用的次数更多(也是我最初猜测的算法)
将当前数字与当前数字索引值+3改为 中间间隔3个

7 5 9 3 1 2 4
第一次:(间隔3个)
1)1 5 9 3 7 2 4
2)1 2 9 3 7 5 4
3)1 2 4 3 7 5 9
第二次:(间隔1个)
4)1 2 4 3 7 5 9
5)1 2 4 3 7 5 9
6)1 2 4 3 7 5 9
7)1 2 4 3 7 5 9
8)1 2 4 3 7 5 9
第三次:(间隔0个)
9 10 11 12 13 14 (重复***处的6个)
总共用了14次

我用了最笨的枚举法列了一下次数,大概看一下区别把。。
对比下来,怎么样都比冒泡次数少。

var arr = [2, 3, 4, 5, 1, 23, 0, 6, 9, 8, 7];

Array.prototype.hillSort = function () {
	let gap = Math.floor(this.length / 2);

	while (gap >= 1) {
		for (let i = 0; i < this.length - gap; i++) {
			if (this[i] > this[i + gap]) {
				swap(this, i, gap + i);
			}
		}
		gap = Math.floor(gap / 2);
    }
    
    return this;
};
  1. 插入排序

     插入排序,类似于打扑克牌,摸牌阶段,你会去找到比摸到的这张牌小的和大的中间,插进去				
    

    例如:
    手牌中有1,7,9,本次摸到了8,从后往前找,找到了9,9的前面有数字7,8比9小,比7大,于是就将8插入到7和9中间
    如果手牌中只有1,则只需要跟他比较,并决定放在他前面 还是他后面
    如果摸到的牌比手牌都小,就需要将该牌放在手牌最前方

Array.prototype.insertSort = function() {
    let newList = [];
    for(let i = 0; i < this.length; i++) {
        const current = this[i];
        console.log(current, newList)
        if(newList.length === 0) {
            newList.push(current);
        } else {
            for(let j = newList.length - 1; j >= 0; j--) {
                let bigItem = newList[j]
                if(current > bigItem) {
                    newList.push(current);
                    break;
                } else {
                    if(j > 0) {
                        var smallItem = newList[j - 1];
                        if(current > smallItem) {
                            newList.splice(j, 0, current);
                            break;
                        }
                    } else {
                        newList.unshift(current)
                    }
                }
            }
        }
    }

    return newList;
}
  1. 快速排序
    假设 中间值为一个标准值,然后将其他的值跟他对比,然后放入左右两侧
    然后再去子集中的中间值作为标准值,对比子集,分为左右两侧(重复操作)
    直到子集长度为1或0时,结束循环

这个速度会比上面几个都快,网上说这个的时间复杂度为O(n*log2n)

Array.prototype.quickSort = function quickSort() {
    function sortFn(array) {
        if(array.length < 2) return array;
        var middle = Math.floor(array.length / 2);
        let newList = [...array];

        let leftArr = [],
            rightArr = [];
        var [reference] = newList.splice(middle, 1);

        for(let i = 0; i < newList.length; i++) {
            let current = newList[i];
            if(current < reference) {
                leftArr.push(current);
            } else {
                rightArr.push(current);
            }
        }
        return [...sortFn(leftArr), reference, ...sortFn(rightArr)]
    }
    return sortFn(this);
}

从网上搜的一张图
在这里插入图片描述
选择排序和冒泡排序比较相似,其他几个我也是刚听说,,之后在更新其他的几个算法吧~
归并排序,堆排序,计数排序,桶排序,基数排序
好好学习,天天向上!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值