• js实现排序算法


     相关概念

    • 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
    • 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
    • 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
    • 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。

    一、冒泡排序

    //冒泡排序
    function bubbleSort (arr) {
        let len = arr.length
        for (var i = 0; i < len-1; i++){ //控制外层循环次数
            for(var j = 0; j < len-i-1; j++) { //控制每个数的比较次数
                if(arr[j] > arr[j+1]) {
                    console.log('>>>>>>')
                    let temp = arr[j+1]
                    arr[j+1] = arr[j]
                    arr[j] = temp
                }
            }
        }
        return arr
    }
    let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46];
    console.log('arr :', bubbleSort(arr));

    二、选择排序

    从0----length-1的范围内选出一个最小值将它放到位置1上,再从1----length-1的范围内选出一个最小值将它放到位置2上,以此类推
    function selectSort(arr){
        let len = arr.length
        let minIndex ,temp 
        for(let i = 0; i < len - 1; i++) {
            minIndex = i //默认最小值
            for (let j = i+1; j < len; j++) {
                if(arr[j] < arr[j+1]) { //寻找最小值
                    minIndex = j //最小值的索引
                }
            }
            //交换默认最小值和最小值的位置
            temp = arr[i]
            arr[i] = arr[minIndex]
            arr[minIndex] = temp
        }
    }

    三、插入排序

    位置n上的数和它前面的n-1位置上数进行比较,如果较小就将位置n-1的数放在n位置上,再和n-2位置上的数进行比较,一直到比到比它小的数出现为止,放在那个比它小的数的后面。
    function insertSort (arr) {
        let len = arr.length
        let preIndex, current
        for(let i = 1; i < len; i++) {
            preIndex = i-1
            current = arr[i]
            //结束的条件是找到已排序的元素小于或者等于当前元素的位置
            while(preIndex >= 0 && arr[preIndex] > current) { //如果前面的数大于当前元素,
                arr[preIndex+1] = arr[preIndex] //就将前一个数向后移
                preIndex-- //指针向前移动
            }
            //将当前元素插入到该位置后
            arr[preIndex+1] = current
        }
    }

    一、阮一峰老师的快排js实现

     思路:

    1、选择数组中间数作为基数,并从数组中取出此基数;

    2、准备两个数组容器,遍历数组,逐个与基数比对,较小的放左边容器,较大的放右边容器;

    3、递归处理两个容器的元素,并将处理后的数据与基数按大小合并成一个数组,返回。

    实现:

    var quickSort = function(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));
     
    };

    总结:

    R的思路非常清晰,选择基数为参照,划分数组,分而治之,对于新手来理解快排的核心思想“参照-划分-递归”,很容易理解 。

    既实现了排序,又符合快速排序的思想,为什么还会为人所诟病呢?原来是因为:

    1、R取基数用的是splice()函数取,而不是算法中常用的取下标。基数只是一个参照对象,在比对的时候,只要能从数组中取到即可,所以只需要知道它的索引即可,调用函数删除基数只会更耗时;

    2、根据基数来划分时,R专门生成两个数组来存储,从而占用了更多的存储空间(增加了空间复杂度)。

    严格上讲,R的代码仅仅是用快速排序的思想实现了排序,也算是快速排序,但是还有很多改进之处。

    二、某乎上的解法

    基本思路跟我上述理解大同小异,主要来看看这篇文章具体的实现过程。下面借用原文的图来讲解(原文的图做的很好就不单独画图了,主要讲一讲原文没解释需要注意的地方,和对该篇文章做一个补充),底部附原文链接。

    1.数组[2,3,1,5,6,4],创建两指针,一个只想头一个指向尾,再确定一个基准数。

    注意:为了方便后面递归是能够确定基准数,这里基准数选取,第一个数或者最后一个数)

     

    2.开始第一次的递归处理,尾指针先从右往左扫,扫到第一个小于(注意是小于,而不是小于等于哦)基准数的位置停住,这时候头指针再从左往右扫,扫到第一个大于基准数的位置停住,这时候是下面的图示状态:

    注意:这里如果基准数选区的第一个数,应该尾指针先往左侧扫,若基准数选取为最后一个属则,应是头指针向往右扫)

     

    交换两个指针所指的数,成为了下面的状态:

    3.两个数交换完毕,右指针此时指的是arr[2] = 3, 左指针指着arr[1] = 1;交换完毕后右指针继续从当前位置往左扫,扫到1的时候发现和左指针相遇了,那么这个时候就结束左右指针的扫描,左右指针同时指着arr[1] = 1,即:

    此时退出循环扫描的过程,交换基准数与左右指针同时所指的数的位置,开头说了,基准数我选择的是arr[0] = 2, 指针指的是arr[1] = 1; 交换过后就变成了:

    这时候就发现基准数已经出现在了它排完序后应该在的位置(排完序后是[1,2,3,4,5,6],2出现在了第2位),比这个基准数小的数组出现在了它的左边([1]出现在了2的左边),比基准数大的出现在了它的右边([3,5,6,4]出现在了2的右边)。

    4.之后的过程就是对左右数组的分别递归处理。

    let quickSort = (arr, begin, end) => {
    //递归出口
        if (begin >= end)
            return;
        var l = begin; // 左指针
        var r = end; //右指针
        var temp = arr[begin]; //基准数,这里取数组第一个数
        //左右指针相遇的时候退出扫描循环
        while (l < r) {
            //右指针从右向左扫描,碰到第一个小于基准数的时候停住
            while (l < r && arr[r] >= temp)
                r--;
            //左指针从左向右扫描,碰到第一个大于基准数的时候停住
            while (l < r && arr[l] <= temp)
                l++;
            //交换左右指针所停位置的数
            [arr[l], arr[r]] = [arr[r], arr[l]];
        }
        //最后交换基准数与指针相遇位置的数
        [arr[begin], arr[l]] = [arr[l], arr[begin]];
        //递归处理左右数组
        quickSort(arr, begin, l - 1);
        quickSort(arr, l + 1, end);
    };
    let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46];
    let end = arr.length-1
    console.log('arr :', quickSort(arr, 0, end));

     推荐比较好的几篇文章

    https://zhuanlan.zhihu.com/p/93129029

    https://www.cnblogs.com/siegaii/p/10744645.html

    https://zhuanlan.zhihu.com/p/93129029

    https://www.cnblogs.com/hjx-blog/articles/9183453.html

    不积跬步无以至千里
  • 相关阅读:
    服务器错误日志
    IfcCurveBoundedSurface
    Ifc发展历史与版本介绍
    IfcCurveBoundedPlane
    IfcRationalBSplineSurfaceWithKnots
    IfcBSplineSurfaceWithKnots
    QDateTime QString
    IFC4 标准中的流程实体
    IFC 标准的定义
    MultipartFile
  • 原文地址:https://www.cnblogs.com/lyt0207/p/12489950.html
Copyright © 2020-2023  润新知