JavaScript数据结构与算法 - 排序算法

1.认识大O表示法

  • 在算法的藐视中,我们可以通过类似的快捷方式来描述计算机算法的效率。
  • 在计算机中,这种粗略的度量被称作“大O”表示法。
  • 在数据项个数发生变化是,算法的效率会跟着发生变化。
  • 我们通常使用一种算法的速度会如何跟随数据量的变化的。
符号名称
O(1)常数的
O(log(n))对数的
O(n)线性的
O(n^2)平方的
O(2^n)指数的

在这里插入图片描述

推导大O表示法

①用常量1取代运行时间中所有的加法常量。
②在修改后的运行次数函数中,只保留最高阶项。
③如果最高阶存在且部位1,则去除与这个项相乘的常数。

2.认识排序算法

本博客主要讲解以下排序

简单排序:冒泡排序,选择排序,选择排序
高级排序:快速排序

3.冒泡排序

 //冒泡排序
       var arrList = [8,6,2,4,5,1,3,10,7,9];

       var len = arrList.length;
      
        function swap(m, n){
            var temp = arrList[m];
            arrList[m] = arrList[n];
            arrList[n] = temp;
        }

        for(var i = len-1; i >=0 ; i--){
            for(var j = 0 ; j < i; j++){
                if(arrList[j] > arrList[j+1]){
                    swap(j,j+1)
                }
            }
        }
        console.log(arrList);
        //(10) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

代码解析:

1: 获取数组的长度.
2: 我们现在要写的外层循环, 外层循环应该让i依次减少, 因此我们这里使用了反向的遍历.
3: 内层循环, 内层循环我们使用 j < i. 因为上面的i在不断减小, 这样就可以控制内层循环的次数.
4: 比较两个数据项的大小, 如果前面的大, 那么就进行交换.
图解(引用codewhy老师的图)
在这里插入图片描述
冒泡排序的效率:
N个数据我们每次比较的次数依次为N-1.N-2,N-3…3,2,3
所以对于N个数据项为(N-1)+ (N-2) + …1 = N*(N-1)/2
运用大O表示法我们可以知道冒泡排序的大O表示法为O(n^2)
交换次数也为O(n^2)

4.选择排序

//选择排序
       var arrList = [8,6,2,4,5,1,3,10,7,9];

       var len = arrList.length;
      
        function swap(m, n){
            var temp = arrList[m];
            arrList[m] = arrList[n];
            arrList[n] = temp;
        }

        for(var i = 0; i < len - 1; i ++){
            var min = i;
            for(var j = min + 1; j < len; j ++){
                if(arrList[min] > arrList[j]){
                    min = j;
                }
            }
            swap(min,i);
        }
        

        console.log(arrList);
        //(10) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

代码解析:

1: 依然获取数组的长度.
2: 外层循环, 我们已经讲过, 需要从外层循环的第0个位置开始, 依次遍历到length - 2的位置.
3: 先定义一个min, 用于记录最小的位置, 内层循环, 内层循环是从i+1位置开始的数据项, 和i位置的数据项依次比较, 直到length-1的数据项.
4: 如果比较的位置i的数据项, 大于后面某一个数据项, 那么记录最小位置的数据.
5: 将min位置的数据, 那么i位置的数据交换, 那么i位置就是正确的数据了.
图解(引用codewhy老师的图)
在这里插入图片描述
选择排序的效率:
选择排序和冒泡排序的比较次数都是N*(N-1)/2, 也就是O(N²).
选择排序的交换次数只有N-1次, 用大O表示法就是O(N).

4.插入排序

//插入排序
       var arrList = [8,6,2,4,5,1,3,10,7,9];

       var len = arrList.length;
      
        function swap(m, n){
            var temp = arrList[m];
            arrList[m] = arrList[n];
            arrList[n] = temp;
        }

        //外层循环从第一个位置获取数据,向前面局部有序进行插入
        for(var i = 1; i < len; i++){
            //内层循环:获取i位置的元素,和前面的数据依次进行比较
            var temp = arrList[i];
            //取j记录i的位置
            var j = i;
            while(arrList[j - 1] > temp && j > 0){
                arrList[j] = arrList[j - 1];
                j--;
            }

            //将当前j位置的数据放进temp即可
            arrList[j] = temp;
        }
        

        console.log(arrList);
        //(10) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

代码解析

1: 获取数组的长度.
2: 外层循环, 从1位置开始, 因为0位置可以默认看成是有序的了.
3: 记录选出的i位置的元素, 保存在变量temp中. i默认等于j
4.内层循环的判断j - 1位置的元素和temp比较, 并且j > 0.那么就将j-1位置的元素放在j位置.j位置向前移.
5: 将目前选出的j位置放置temp元素.
插入排序的比较效率:最大为N*(N-1)/2 ,平均为N*(N-1)/4
在这里插入图片描述

5.快速排序(分而治之的思想)

快速排序思想

1.确定基准数,我们把数组的第一个元素作为基准数。
基准数的作用就是我们一次计算结束后,把小于基准数额元素都放到基准数的左边,大于等于基准数的元素都放到基准数的右边。例如,我们一次计算之后的T是这样的:T = [3,1,2,5,4 ,6 ,9,7,10,8]
2.确定哨兵用两个变量i和j,分别指向序列最左边和最右边。我们为这两个变量起个好听的名字“哨兵i”和“哨兵j”。刚开始的时候让哨兵i指向序列的最左边,让哨兵j指向序列的最右边。
首先哨兵j开始出动。哨兵j一步一步地向左挪动(即j–),直到找到一个小于6的数停下来。接下来哨兵i再一步一步向右挪动(即i++),直到找到一个数大于6的数停下来。最后哨兵j停在了数字5面前,哨兵i停在了数字7面前。接下来开始哨兵j继续向左挪动。进行交换
他发现了4(比基准数6要小,满足要求)之后停了下来。哨兵i也继续向右挪动的,他发现了9(比基准数6要大,满足要求)之后停了下来。此时再次进行交换。
第二次交换结束,“探测”继续。哨兵j继续向左挪动,他发现了3(比基准数6要小,满足要求)之后又停了下来。哨兵i继续向右移动,糟啦!此时哨兵i和哨兵j相遇了,哨兵i和哨兵j都走到3面前。说明此时“探测”结束。我们将基准数6和3进行交换。交换之后的序列如下:
3.交换基准位到此第一轮“探测”真正结束。此时以基准数6为分界点,6左边的数都小于等于6,6右边的数都大于等于6。然后对6两边的数组做递归处理即可。

图示快速排序算法:
在这里插入图片描述
代码示例:

  /**
题目:快速排序算法
思路:两个哨兵,i,j,j从右边找比基数小的,i从左边找比基数大的,然后交换两个目标元素的位置,直到i=j,然后交换i和基数的位置,递归处理。
**/
        function quick_sort(arr, left, right) {
            //哨兵i
            var i = left;
            //哨兵j
            var j = right; 
            //基准值
            var key = arr[left]; 
            //如果数组只有一个元素
            if (left >= right) { 
                return;
            }

            while (i < j) {
                //从右边向左找第一个比key小的数,找到或者两个哨兵相碰,跳出循环
                while (arr[j] > key && i < j) { 
                    j--;
                }
                //从左边向右找第一个比key大的数,找到或者两个哨兵相碰,跳出循环,这里的=号保证在本轮循环结束前,key的位置不变,否则的话跳出循环,交换i和left的位置的时候,left位置的上元素有可能不是key
                while (arr[i] <= key && i <j) { 
                    i++;
                }
                /**
                  代码执行道这里,1、两个哨兵到找到了目标值。2、j哨兵找到了目标值。3、两个哨兵都没找到(key是当前数组最小值)
                **/
                if (i < j) { //交换两个元素的位置
                    var temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;

                }
            }

            //交换基准位
            arr[left] = arr[i] //
            arr[i] = key;
            
            //重新递归排序key两边的两个数组
            quick_sort(arr, left, i - 1);
            quick_sort(arr, i + 1, right);
        }

        var arr = [6,1,2,5,4,3,9,7,10,8];
        console.log(arr);
        //[6, 1, 2, 5, 4, 3, 9, 7, 10, 8]
        quick_sort(arr, 0, arr.length - 1);
        console.log(arr);
        //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值