冒泡.选择排序以及数组常用方法

75 阅读10分钟

数组

与变量相比  变量只能储存一个值
数组的作用:数组可以储存很多值,一组数据的集合储存在单个变量下的优雅方式(Array)
 var arr = [123,50,60,70,]; // 常用
 var arr1 = [];  创建了一个空数组
  字面量创建数组  字面量  一种固定值的表示方法
 var arr =new Array();
 利用new (创建数组)

 var arr2 = [1,3,'pink老师',true];
      数组里面的数据一定用逗号分隔
      数组里面的数据 称为 数组元素

      声明数组并赋值称为数组的初始化
      数组里面的数据可以是任意类型的
        // 数组的长度是元素的个数 不要跟索引号混淆
        // arr.length 动态检测数组元素的个数

        /* 求数组的最大值
        1.准备一个容器
        2.遍历数组
        3.每一个元素都和sum比较
        4.每次大于sum都放入sum里面
        5.直到不大于sum为止然后打印它
        */

        arr = [10, 20, 99, 37, 51,]
        // 方法一
        var sum = 0;
        for (var i = 0; i < arr.length; i++) {
            if (arr[i] > sum) {
                sum = arr[i];
            }
        }
        console.log(sum);
        // 方法二
        var sum = arr[0];
        for (var i = 1; i < arr.length; i++) {
            if (arr[i] > sum) {
                sum = arr[i];
            }
        }
        console.log(sum);
//算法: 冒泡排序
        var arr = [9, 8, 7, 6, 5, 4, 3, 2, 1];
        console.log(arr);
        for (var j = 0; j < arr.length - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                var temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
        console.log(arr);
        for (var j = 0; j < arr.length - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                var temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
        console.log(arr);


        // 外层循环决定执行多少次
        for (var i = 0; i < arr.length; i++) {

            // 冒泡排序的核心代码
            for (var j = 0; j < arr.length - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    var temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        console.log(arr);//[1, 2, 3, 4, 5, 6, 7, 8, 9]
        // //第一次循环

        arr1 = [9, 8, 7, 6, 5, 4, 3, 2, 1,];
        for (var i = 0; i < arr.length - 1; i++) {
            for (var j = 0; j < arr1.length - 1; j++) {
                var temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
        console.log(arr);//[1, 2, 3, 4, 5, 6, 7, 8, 9]

冒泡排序及其多种优化方法

算法
  • 解决某一个问题, 性能相对更好的哪一个解决方案
小案例
  • 需求: 对比数组前一项与他的后一项, 如果前一项的值大于后一项的, 那么将前后两项交换位置
    1.for循环遍历数组
    2.对比数组前一项与他的后一项,如果前一项的值大于后一项的(if分支)
    3.前后两项交换位置 (引入第三个变量)
var arr = [9, 8, 7, 6, 5, 4, 3, 2, 1];
         console.log('原数组:',arr);[9, 8, 7, 6, 5, 4, 3, 2, 1]
        // 算法 : 冒泡排序 (未优化)
        for (var k = 0; k < arr.length; k++) {
            // k的范围为  0~8
            for (var i = 0; i < arr.length; i++) {
                // i的范围为 0~8
                if (arr[i] > arr[i + 1]) {
                    var tem = arr[i]    // 存储最开始 [0] 的值
                    arr[i] = arr[i + 1]
                    arr[i + 1] = tem     // 需要使用 最开始 [0] 的值
                }
            }
        }
        console.log(arr);  // [1, 2, 3, 4, 5, 6, 7, 8, 9]
步骤解析:
// k ==1  2次循环  i ==1   
        if (arr[1] > arr[2]) {
            var tem = arr[1]
            arr[1] = arr[2]
            arr[2] = tem
        }// k ==2  3次循环  i ==2   
        if (arr[2] > arr[3]) {
            var tem = arr[2]
            arr[2] = arr[3]
            arr[3] = tem
        }// k ==3  4次循环  i ==3   
        if (arr[3] > arr[4]) {
            var tem = arr[3]
            arr[3] = arr[4]
            arr[4] = tem
        }
        // k ==4  5次循环  i ==4   
        if (arr[4] > arr[5]) {
            var tem = arr[4]
            arr[4] = arr[5]
            arr[5] = tem
        }
        // k ==5  6次循环  i ==5   
        if (arr[5] > arr[6]) {
            var tem = arr[5]
            arr[5] = arr[6]
            arr[6] = tem
        }// k ==6  7次循环  i ==6   
        if (arr[6] > arr[7]) {
            var tem = arr[6]
            arr[6] = arr[7]
            arr[7] = tem
        }
        // k ==7  8次循环  i ==7  
        if (arr[7] > arr[8]) {
            var tem = arr[7]
            arr[7] = arr[8]
            arr[8] = tem
        }
        // k ==8  9次循环  i ==8   
        if (arr[8] > arr[9]) {
            var tem = arr[8]
            arr[8] = arr[9]
            arr[9] = tem
        }
        //因为最后一次
         if(arr[8] > arr[9]) {
            var tem = arr[8]
            arr[8] = arr[9]
            arr[9] = tem
         }
        // i 超过 数组的长度 没有意义
  • 优化方案
// 优化一 
        var arr = [9, 8, 7, 6, 5, 4, 3, 2, 1];
        //  下标   0  1  2   3  4  5  6  7  8     length: 9 
        console.log('原素组:', arr);
        for (var k = 0; k < arr.length - 1; k++) {
            // 外部循环决定内部循环的次数  0~8
            for (var i = 0; i < arr.length - 1; i++) {
                // 遍历数组
                if (arr[i] > arr[i + 1]) {
        // 对比数组前一项与他的后一项,如果前一项的值大于后一项的(if分支)
                    var temp = arr[i];  // 储存最开始[0]的值
                    arr[i] = arr[i + 1];
                    arr[i + 1] = temp; // 需要使用最开始[0]的值
                    // 前后两项交换位置
                }
            }
        }
        console.log(arr);
步骤解析:
   第 1 次循环确定了 [8]    [8, 7, 6, 5, 4, 3, 2, 1, 9]
   第 2 次循环确定了 [7][8]    [7, 6, 5, 4, 3, 2, 1, 8, 9]
   第 3 次循环确定了 [6][7][8]    [6, 5, 4, 3, 2, 1, 7, 8, 9]
   第 4 次循环确定了 [5][6][7][8]    [5, 4, 3, 2, 1, 6, 7, 8, 9]
   第 5 次循环确定了 [4][5][6][7][8]    [4, 3, 2, 1, 5, 6, 7, 8, 9]
   第 6 次循环确定了 [3][4][5][6][7][8]    [3, 2, 1, 4, 5, 6, 7, 8, 9]
   第 7 次循环确定了 [2][3][4][5][6][7][8]    [2, 1, 3, 4, 5, 6, 7, 8, 9]
   第 8 次循环确定了 [1][2][3][4][5][6][7][8]    [1, 2, 3, 4, 5, 6, 7, 8, 9]
   第 9 次循环确定了 [1][2][3][4][5][6][7][8]    [1, 2, 3, 4, 5, 6, 7, 8, 9]

   分析之后发现, 最后一轮外层循环是没有意义的, 所以我们可以减少最后一次循环
   也就是说, 外层循环的结束条件应该调整为 k < arr.length - 1
// 个人书写的代码
//    循环次数   (i)     遍历次数
        // k ==0    1     0         1

        for (var i = 0; i < arr.length - 1; i++) {
            if (arr[0] > arr[1]) {
                var temp = arr[0];
                arr[0] = arr[1];
                arr[1] = temp;
            }
        }
        k ==1    2      1         2
        for (var i = 1; i < arr.length - 1; i++) {
            if (arr[1] > arr[2]) {
                var temp = arr[1];
                arr[1] = arr[2];
                arr[2] = temp;
            }
        }
        // ...7                    8                7                8
        // k < arr.length - 1   arr.length - 1  < arr.length - 1  arr.length - 1

  • 优化二
var arr = [9, 3, 6, 2, 4, 1, 8, 5, 7]
        //  下标     0   1  2  3  4  5  6  7  8        length: 9
        console.log('原数组', arr)
        // // 优化1
        for (var k = 0; k < arr.length; k++) {  // 决定内部的 冒泡排序执行多少次
        内循环: 冒泡排序的核心代码
            /**
             *
             * for (var i = 0; i < arr.length-1; i++) {
             *      当前 i 的值为 0~8
             *
             *      如果最后一轮循环的时候, i === 8
             *          分支语句: if (arr[i] > arr[i + 1])  -> if (arr[8] > arr[9])
             *          因为没有 下标9 的项, 所以当前循环最后一轮是没有意义的, 我们应该减少最一轮循环
             *          所以循环的结束条件应该修改为 i < arr.length - 1
             */
            for (var i = 0; i < arr.length - 1; i++) {
                if (arr[i] > arr[i + 1]) {
                    var tem = arr[i]
                    arr[i] = arr[i + 1]
                    arr[i + 1] = tem
                }
            }
        }
        console.log(arr);

//  优化三
        var arr = [9, 8, 7, 6, 5, 4, 3, 2, 1]
        // 下标     0 1  2  3  4  5  6  7  8        length: 9
        // console.log('原数组', arr)

        /**
         *  经过这个打印之后, 我们发现, 每一轮循环, 都有一些没有必要的判断
         *  规律是: 每一轮判断的执行次数, 减少 k 次
         * 
         *  因为 内部的 if 判断, 是由内循环决定次数的, 所以我们在 内循环的执行次数上, 加上一个 - k
         * 
         *  所以最后的 内循环结束条件: i < arr.length - 1 - k
        */
        for (var k = 0; k < arr.length - 1; k++) {
            // 决定内部的 冒泡排序执行多少次
            // 内循环: 冒泡排序的核心代码
            // console.log('当前是第', k + 1, '次', '当前k==', k);
            for (var i = 0; i < arr.length; i++) {
                //   i   0~7   8次
                if (arr[i] > arr[i + 1]) {
                    var temp = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = temp;
                }
            }
            // console.log('=============================');
        }
        console.log(arr);
//步骤解析
// k  循环次数   i   遍历次数   

        // 0     1       0     1         
        if (arr[0] > arr[1]) {
            var temp = arr[0];    //[8, 7, 6, 5, 4, 3, 2, 1, 9]
            arr[0] = arr[1];
            arr[1] = temp;
        }
        // 1     2      1     2
        if (arr[1] > arr[2]) {
            var temp = arr[1];    //[7, 6, 5, 4, 3, 2, 1, 8, 9]
            arr[1] = arr[2];
            arr[2] = temp;
        }
        // 2     3      2     3
        if (arr[2] > arr[3]) {
            var temp = arr[2];  //[6, 5, 4, 3, 2, 1, 7, 8, 9]
            arr[2] = arr[3];
            arr[3] = temp;
        }

        //...
        // 7     8      7     8
        if (arr[7] > arr[8]) {
            var temp = arr[8];  //[1, 2, 3, 4, 5, 6, 7, 8, 9]
            arr[7] = arr[8];
            arr[8] = temp;
        }
        // 8     9      8     9
        if (arr[8] > arr[9]) {
            var temp = arr[9];  //[1, 2, 3, 4, 5, 6, 7, 9, 9]
            arr[8] = arr[9];
            arr[9] = temp;
        }
        // 没有任何意义 k 的值为 8 和 k 的值为 7  是一样的没有意义  

选择排序

小案例
  • 找到最小值
var arr = [2, 6, 3, 1, 9, 5, 8, 7, 4];
        //  索引为  0  1  2  3  4  5  6  7 8
        console.log(arr);
        for (var k = 0; k < arr.length; k++) {
            // 创建一个变量,储存当前假设的最小值的下标
        }
        var sum = 0;

        for (var i = 1; i < arr.length; i++) {
            if (arr[sum] > arr[i]) {
                sum = i;
            }
        }
        console.log(sum);// 最小值的索引为3

        var temp = arr[0];
        // 把真实的最小值给第三个变量
        arr[0] = arr[sum];
        // 把求出的最小值即真实最小值赋值给arr[0]
        // 即真实最小值位置编程了第一个位置
        arr[sum] = temp;
        // 换过来的值换到原来真实最小值的位置

        console.log(arr);
  • 优化二
步骤分析:
           //第几次循环 //   sum (假设真实数)    与数组的元素(i)进行比较   真实最小值的索引  
//  k ===0      1                    0                    1                   0
//  k ===1      2                    1                    2                   1
//  k ===2      3                    2                    3                   2  
for (var k = 0; k < arr.length; k++) {
            var sum = k;
            for (var i = k + 1; i < arr.length; i++) {
                if (arr[sum] > arr[k+1]) {
                    sum = k+1;
                }
            }
            var temp = arr[k];
            arr[k] = arr[sum];
            arr[sum] = arr[temp];
        }
        console.log(arr);
步骤解析:
var sum = 0;
        for (var i = 1; i < arr.length; i++) {
            if (arr[sum] > arr[i]) {
                sum = i;
            }
        }
        var temp = arr[i];
        arr[i] = arr[sum]
        arr[sum] = temp;
        console.log('选择排序后: ', arr);

        var sum = 1;
        for (var i = 2; i < arr.length; i++) {
            if (arr[1] > arr[2]) {
                sum = 2;
            }
        }
        var temp = arr[2];
        arr[2] = arr[1]
        arr[1] = temp;
        console.log('选择排序后: ', arr);

        var sum = 2;
        for (var i = 3; i < arr.length; i++) {
            if (arr[2] > arr[3]) {
                sum = 3;
            }
        }
        var temp = arr[3];
        arr[3] = arr[2]
        arr[2] = temp;
        console.log('选择排序后: ', arr);
步骤解析二
var sum = 1;
        for (var i = 2; i < arr.length; i++) {
            if (arr[sum] > arr[i]) {
                sum = i;
            }
        }
        console.log(sum);// 最小值的索引为3

        var temp = arr[1];
        // 把真实的最小值给第三个变量
        arr[1] = arr[sum];
        // 把求出的最小值即真实最小值赋值给arr[0]
        // 即真实最小值位置编程了第一个位置
        arr[sum] = temp;
        // 换过来的值换到原来真实最小值的位置
        1;


        var sum = 2;
        for (var i = 3; i < arr.length; i++) {
            if (arr[sum] > arr[i]) {
                sum = i;
            }
        }
        console.log(sum);// 最小值的索引为3

        var temp = arr[2];
        // 把真实的最小值给第三个变量
        arr[2] = arr[sum];
        // 把求出的最小值即真实最小值赋值给arr[0]
        // 即真实最小值位置编程了第一个位置
        arr[sum] = temp;
        // 换过来的值换到原来真实最小值的位置
数据类型之间的区别
  • 基本数据类型
  • 复杂数据类型
存储的区别

1.基本数据类型(string, numbe, undefined, null, boolean) 会直接将数据类型存储到 栈内存中
2.复杂数据类型(object, array, function)
将数据本体, 存放在堆内存中, 然后将指向堆内存的地址, 存储在 变量名中, 最后变量名存储在 栈内存中

比较的区别

1.基本数据类型

  • 直接将数据进行对比 2.复杂数据类型
  • 因为变量内部存储的是 一个地址, 所以对比时, 对比的是地址, 而不是真正的值
代码解析:
        var arr  = [1,2,3,4,5,];      
        var arr1 = [1,2,3,4,5,];
        console.log(arr===arr1);// false
赋值的区别

1.基本数据类型
直接将数据类型给另一个变量;赋值完成之后, 两个变量没有任何关系

类似于, 我有一张考试卷子, 我复制出来一份给你, 然后你对你的卷子有任何修改, 都不会影响我这一张卷子
2.复杂数据类型
因为复杂数据类型的变量名中 存储的是指向一个堆内存的地址, 所以在做赋值的时候, 是把这个地址赋值给另一个变量了,所以修改另外一个变量的时候, 会影响自身

类似于: 我有一个房间的钥匙, 然后我将钥匙复制一份, 给你一个, 你后续能够进入这个房间了, 后续如果你对这个房间做了任何修改在我进入房间的时候, 我都能看到

var arr = 100;
    var num = arr;  // 直接将 arr 内部的数据赋值给另一个变量, 也就是 num
    num++;
    console.log(num,arr);//101 100

    var arr =[1,2,3]
    var newArr = arr
    newArr[0] = 100
    console.log(arr) // [100,2,3]
传参的区别

1.基本数据类型

  • 将数据拷贝一份传递给形参, 在函数内对形参的修改并不会影响外界
  1. 复杂数据类型
    • 将变量内部存储的地址, 赋值给形参, 也就是说, 函数内部的形参, 和外部的变量, 共同享用同一个地址所以在函数内对形参的修改会影响外界
代码解析:
function fn(str){
    str ='QF001'
    console.log('str:', str) //QF001
}
var winStr ='qwer'
fn(winStr)
console.log('winStr:', winStr) //qwer

小案例(1):
   function fn2(arr){
           arr[0]=100
           console.log('arr:', arr) //[100,2,3]
        //   实际上是  arr =winArr 即 [1,2,3]
        // 利用复杂数据类型的传参区别 arr 的地址和 winArr相同
        // 所以 arr = [100,2,3]
       }
       var winArr =[1,2,3];
       fn2(winArr)
       console.log('winArr:',winArr)//[100,2,3]


小案例(2):
        var obj = {
            name: 'QF001'
        }
        function fn(obj) {
        // 相当于obj.name = 'QF001'
        // 利用复杂数据类型的传参区别  全局变量的name:'QF002'
            obj.name = 'QF002'
            obj = {}
            // 将一个空对相想赋值给变量obj
            // 并且在当前作用域内找  obj.name = 'QF002'
            obj.name = 'QF003'  
            console.log(obj.name);//QF003
        }
        fn(obj);
        console.log(obj.name);// QF002

数组的常用方法

1. push() 
  语法: 数组.push()
  作用: 将这个 "数据", 追加到数组的末尾, 向数组末尾, 添加新数据
  返回值: 追加新数据后, 数组的最新的长度 length
2.pop()
  语法: 数组.pop()
  作用:  删除数组的最后一项
  返回值: 删除的哪一项对应的值
3.unshift()
  语法:   数组.unshift(数据)
  作用:   将这个 "数据", 添加到数组的开头
  返回值: 追加新数据后, 数组的最新长度 length
4.shift()
  语法: 数组.shift()
  作用:   删除数组的第一项
  返回值: 删除的哪一项对应的值
5.reverse()
  语法: 数组.reverse()
  作用: 反转数组
  返回值: 反转后的数组

上述方法, 都能够改变原数组

代码演示:
        //1. push
        var arr = [1, 2, 3]
        var ars = arr.push(4); // 将 数字 4, 追加到数组的末尾, 并将数组最新的长度, 赋值给变量 res
        arr.push(5)            // 将数字 5, 追加到数组的末尾(这种写法更为常见)
        console.log(arr); // [1, 2, 3,4]
       
         2.pop();
        var arr = [1, 2, 3];
        var res = arr.pop();
        arr.pop();
        console.log(res);//3
        console.log(arr);//[1]

        // 3.unshift
        var arr = [1, 2, 3];
        var res = arr.unshift(0);
        console.log(res);// 4
        console.log(arr);// [0,1,2,3,]

        // 4.shift
        var arr = [1, 2, 3]
        var res = arr.shift()
        console.log(res)    // 1
        console.log(arr)    // [2, 3]

        // 5. reverse
        var arr = [1, 2, 3]
        var res = arr.reverse()
        console.log('res', res) // [3,2,1]
        console.log('arr', arr)//[3,2,1]
      ```