自学js第六天:JS数组和算法

这篇博客详细介绍了JavaScript数组的概念、创建方式、属性、元素访问、遍历、多维数组、类型判断、数组方法(如join、push、pop、shift等)以及排序算法(冒泡排序、选择排序、插入排序)。还探讨了数组的引用类型特性,强调了数组的隐式转换规则和数组的浅拷贝操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JS数组

PS;

数组下标,超过内容实际长度, 则返回undefined
从数组中pop/shift删除的元素(当数组删光了,则返回undefined)。
function函数没有return返回值时,也会默认返回undefined的.
indexOf数组方法(通过元素找下标,没有找到则返回-1 )
String(num)[1] 字符串也可以根据下标取值

1.为什么要学习数组引用类型

之前学习的数据类型,只能存储一个值 比如:Number/String。我们想存储班级中所有学生的姓名,此时该如何存储?

 <script>

    // switch 打印星期几 0为星期日 1 - 6分别对应星期一到星期六

    var day = 0;
    switch (day) {
      case 0:
        console.log('星期日');
        break;
      case 1:
        console.log('星期一');
        break;
      case 2:
        console.log('星期二');
        break;
    }
 
    //上面的switch太累赘了,因此可以用数组下标映射去代替case的0 1 2...
    //数组映射 ---->用空间换时间 分支值或者可能性非常多并且有规律的时候
    var weekDay = ['日', '一', '二', '三', '四', '五', '六'];
    console.log('星期' + weekDay[day]);

  </script>

2.数组的概念

所谓数组,就是将多个元素(通常是同一类型,但JS的数组可以放不同类型…)按一定顺序排列放到一个集合中,那么这个集合我们就称之为数组。

3.数组的定义

数组是一个有序的列表,可以在数组中存放任意的数据,并且数组的长度可以动态的调整。

一.如何创建数组

1.通过动态小括号new实例化创建:new Array(length);
var arr = new Array(3); 
//只写一个参数,创建一个长度为3的数组 , 数组中每一项都为 空置empty [empty,empty,empty]

var arr = new Array(1,2,3,4); 
//实例化多个数组参数,  会生成具体对应内容参数内容的数组.
2.通过静态中括号数组字面量创建数组:var arr2 = [xx, xx, xx];
// 创建一个空数组
var arr1 = []; 
// 创建一个包含3个数值的数组,多个数组项以逗号隔开
var arr2 = [1, 3, 4]; 
// 创建一个包含2个字符串的数组
var arr3 = ['a', 'c']; 

二.数组内部的各个属性

<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>数组</title>
</head>

<body>
  <script>

    var names = '张三,李四,王五,赵六';

    names = '张三,李四,王九,赵六';

  
    //动态创建数组 
    //单个参数
     var arr = new Array(3);  
     console.log(arr); //[empty × 3]  
     console.log(arr[0]); //undefined
     console.log(arr[1]); //undefined
     console.log(arr[2]); //undefined
     console.log(arr[3]); //undefined 超过数组内容下标,也是undefined
    //动态数组内没有内容时输出这个数组则是empty,  输出单个是默认值undefined

    //多个参数,则给具体字面值内容了
     var arr = new Array(1, 2, 3, 4, 5); 
     console.log(arr); //[1, 2, 3, 4, 5]  具体内容
     console.log(arr[0]); //1

      

    //静态创建数组 
    //JS用常用写法:给具体字面值
    var arr = [1, 2, 3, 4, 5];
    arr = ['哈哈', 1, true, NaN, null];

    console.log(arr, arr.length); //JS可以把整个数组打印出来,输出数组长度
    arr[2] = false;  //通过下标改变数组的内容
    console.log(arr[2]); //输出数组第几个下标内容

    arr.length = 2;  //改变数组的长度,再输出数组
    console.log(arr);

    //PS: 字符串的长度无法改变
    var str = '海牙老师真的好好看啊'; 
    str.length = 2;
    console.log(str.length);  //还是10

  </script>
</body>

</html>


三.如何获取数组元素

数组的取值(通过索引下标)

// 格式:数组名[下标]	下标又称索引
// 功能:获取数组对应下标的那个值,如果下标不存在,则返回undefined。
var arr = ['red', 'green', 'blue'];
arr[0];	// red
arr[2]; // blue
arr[3]; // 这个数组的最大下标为2,因此返回undefined

四.数组元素赋值或修改(JS数组可以跨越长度跨界去赋值和修改不会报错)

数组的赋值

var arr = ['red', 'green', 'blue'];

arr[2] = 'yellow'; //给下标为2的数组元素赋值 如果该元素本身有值会进行覆盖

arr[3] = '#368'; // 给下标为3的数组元素赋值 如果该元素不存在就新增

arr //["red", "green", "yellow", "#368"]

arr[5] = '#f60'; //跨位进行赋值  则中间空位显示 empty (空置)

arr // ["red", "green", "yellow", "#368", empty, "#f60"]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VwsLqE38-1620234826825)(C:\Users\tuyue\AppData\Local\Temp\1615268903034.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T3dsbeRo-1620234826834)(C:\Users\tuyue\AppData\Local\Temp\1615268589581.png)]

五,如何遍历数组:

遍历:遍及所有,对数组的每一个元素都访问一次就叫遍历。

数组遍历的基本语法:
for(var i = 0; i < arr.length; i++) {
	// 数组遍历的固定结构
}
<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>数组遍历</title>
</head>

<body>
  <script>
    //犯罪现场有4个嫌疑人 让证人一一辨认  嫌疑人名字叫王五
    //
    var suspects = ['张三', '李四', '王五', '赵六']; //4 
    
    for (var i = 0; i < suspects.length; i++) {// 0 - 3 
      console.log( suspects[i]);
      if (suspects[i] === '王五') {
        console.log('就是他:'+ suspects[i] + ","+ (i+1) + '号嫌疑人');
      }
    }

    //ES6: for idx in   有可能乱序 (下标变为idx)
    for (var idx in suspects) {
      console.log(idx, suspects[idx]);
    }


    //ES6: for item of  (快速遍历,下标变为item)
    for (var item of suspects) {
      console.log(item);
    }





    // var a = '张三', b = '李四', c = '王五', d = '赵六';
    // if (a === '张三') {

    // }

    // if (b === '张三') {

    // }

    // if (c === '张三') {

    // }

    // if (d === '张三') {

    // }



  </script>
</body>

</html>
for in 遍历(不推荐)
for(var key in arr){
    console.log(key,arr[key]);  //key 为下标 arr[key]为对应key下标的值
}

使用for-in可以遍历数组,但是会存在以下问题:

1.index索引为字符串型数字(注意,非数字),不能直接进行几何运算。

2.遍历顺序有可能不是按照实际数组的内部顺序(可能按照随机顺序)。

3.使用for-in会遍历数组所有的可枚举属性,包括原型。例如上例的原型方法method和name属性都会被遍历出来,通常需要配合hasOwnProperty()方法判断某个属性是否该对象的实例属性,来将原型对象从循环中剔除。
for of 遍历
for(var key of arr){
    console.log(key); 
}
相比 for-in 不会出现顺序错乱的问题 也不会遍历出所有可枚举属性 

六.多维数组

数组中包含数组的话称之为多维数组。 您可以通过将两组方括号链接在一起来访问数组内的另一个数组

使用最多也就是二维数组

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

七.数组类型判定与隐式转换

var arr = [1,2,3];

typeof arr //'object' 数组是object

Number(arr) //NaN

String(arr) // '1,2,3'

Bollean(arr) // true

[] == [] //false

arr + '海牙' //'1,2,3海牙'

arr / 2 // NaN

arr + [] // '1,2,3'

[] + [] //''

[2]  - 1 //1

[1,]  - 1 //0

[1,2]  - 1 // NaN

!![] // true
死记数组的隐转:(就单项内容且为数字或者数字字符串的时候时候可以隐转,其他都是NAN)
<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>数组类型转换</title>
</head>

<body>
  <script>
    var arr = [1, 2, 3];

    console.log(typeof arr); //数组的类型object

    console.log(Array.isArray(123)); //验证是否为数组的方法

    [] == []; //对象和对象之间永远不相等

    //因为arr1和arr2数组之间存的内存地址0xfffA , 0Xfff1肯定不同,
    //因此无法通过==/===等号来判断,java可以通过equals来比较地址具体内容. 

    var arr1 = [1, 2, 3];
    var arr2 = [1, 2, 3];
    console.log(arr1 == arr2); //false
    console.log(arr1 === arr2);//false
    console.log([1, 2, 3]);
    // !-[-1,]


    //数组就一项可以且是数值或者数字字符串的,则都可以直接转number
    console.log(Number([-1])); //-1
    console.log(Number([1])); //1
    console.log(+[-1]); //-1
    console.log(-[-1]); //1  
    console.log(-[-1,]); //1  
    console.log(+["1"]); //0
    console.log(-["2"]); //-2

    //数组大于一项且不管是什么,都不能转number直接NAN
    console.log(Number([-1,-2])); //NAN
    console.log(+[-1,-2]);//NAN
    console.log(+["123","123"]); //NAN
    console.log(+[true]); //NAN
    console.log(+[false]); //NAN

    //特殊number隐式:带undefined数组和null数组
    //和[]空数组和""空字符串数组是被转为0的...
    console.log(+[undefined]); //0
    console.log(-[undefined]); //-0
    console.log(+[null]); //0
    console.log(-[null]); //-0
    console.log(+[]); //0
    console.log(-[]); //-0
    console.log(+[""]); //0
    console.log(-[""]); //-0
  
    

  </script>
</body>

</html>

八.数组基础方法

数组的方法有很多,在我们学习完函数 作用域 对象之前我们先了解一些数组的基础方法

1.isArray(obj)

用于确定传递的值是否是一个 Array。

Array.isArray([1, 2, 3]);  
// true
Array.isArray({foo: 123});  object
// false
Array.isArray("foobar");   
// false
Array.isArray(undefined);  
// false
参数
obj 需要检测的值
返回值
如果值是Array 则为true; 否则为false

2.join(合并为字符串)

join方法将一个数组的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。

(把数组内容转为成一个整体字符串,并默认用,逗号分隔符separator分隔开)

const elements = ['火', '空气', '水'];

console.log(elements.join());
// "火,空气,水"   变为一个整体字符串

console.log(elements.join(''));
// "火空气水"

console.log(elements.join('-'));
// "火-空气-水"

    //join
    var arr = ['海', '牙', '真', '可', '爱', 1, false, null, undefined];
    var str = arr.join('-');
    // console.log(str);
    //null, undefined 在数组可以存的,但是join方法会把null, undefined变为空字符串无法显示
    //海-牙-真-可-爱-1-false

参数
separator 可选 指定分隔符号 该参数默认值为","
返回值
一个所有数组元素连接的字符串。如果 arr.length 为0,则返回空字符串。

注意

如果一个组数内容的元素为 undefinednull,则使用join它会被转换为空字符串即不存在了。

3.push(尾插法,返回新长度,element1,…,elementN)

方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。

var animals = ['猪', '狗', '牛'];

var count = animals.push('大象');
console.log(count);
// 4
console.log(animals);
// ['猪', '狗', '牛','大象']

animals.push('鸡', '鸭', '鹅');
console.log(animals);
//['猪', '狗', '牛', '大象', '鸡', '鸭', '鹅']


参数
elementN 可选多个参数
参数会添加到数组末尾
返回值
当调用该方法时,新的 length 属性值将被返回。
push综合案例:js中for循环一维数组追加二维数组的问题
 <script>
 //方法一:
     var count = 7;
// 这个要移到for里面,不然每次都往这个数组里加数据
// var GYR = [];
var gyr = []; //最终放七个GRY一维数组的二维容器
for(var i = 0; i < count; i++) {    //放七个一维数组进去即可
    //GRY每次放完123一维进去进入gry,就要清空长度或者重新创建新的,否则每次都是放之前累加过全部数据放进去,然后当成一次新的全部输出.(GRY就是一个装123的一维,装一次清空一次盒子再装,然后每次可以再放进gry,让gry一维变二维,最终放七个GRY一维数组的二维容器)
    var GYR = []; //一维数组
    var XM = 1;
    var XB = 2;
    var NL = 3;
    GYR.push(XM,XB,NL); 
    gyr.push(GYR); 
}
alert(gyr); 


//方法二:
var count = 7;
var GYR = [];
var gyr = [];
for(var i = 0; i < count; i++) {
    GYR.length = 0; //更新长度为0,重新放
    var XM =1;
    var XB = 2;
    var NL = 3;
    GYR.push(XM,XB,NL);
    gyr.push(GYR);
}
alert(gyr);
  </script>

4.unshift(头插法,返回值是一个新长度length)

方法将一个或多个元素添加到数组的前端,并返回该数组的新长度。

var animals = ['猪', '狗', '牛'];

var count = animals.unshift('大象');
console.log(count);
// 4
console.log(animals);
// ['大象', '猪', '狗', '牛']

animals.unshift('鸡', '鸭', '鹅');
console.log(animals);
//[ '鸡', '鸭' , '鹅','大象','猪', '狗', '牛' ]


参数
elementN 可选多个参数
参数会添加到数组末尾
返回值
当调用该方法时,新的 length 属性值将被返回。

5.pop(尾删法,返回删除的元素)

方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。

这个pop不能放参数,只能是用一次,删除最后一个,用一次再删除最后一个,不能具体删除某一个.
var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆'];

console.log(plants.pop());
//  "土豆"

console.log(plants);
// ['西红柿', '黄瓜', '芹菜', '豆角']

plants.pop();

console.log(plants);
// ['西红柿', '黄瓜', '芹菜']


参数
返回值
从数组中删除的元素(当数组为空时返回undefined)

6.shift(头删法,返回删除的元素值)

方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。

var array = [1, 2, 3];

var firstElement = array.shift();

console.log(array);
//  Array [2, 3]

console.log(firstElement);
//  1


参数
返回值
从数组中删除的元素; 如果数组为空则返回undefined 。 

7.slice(有参,数组浅拷贝,返回一个新的数组对象[ ])

1.切割方法返回一个新的数组对象,原始数组不会被改变。

这一对象是一个由 beginend 决定的原数组的浅拷贝(包括 begin(起始下标),不包括end(结束下标))。原始数组不会被改变。

2.slice方法可以作为数组浅拷贝, 即如果不传参 默认切割复制整个自己数组,然后给返回一个新数组引用对象 , 但并不是单纯的下面的这种引用复制,下面这种引用复制一旦改变内容则两个引用会一起改变

而引用类型进行直接变量赋值操作时 因为数组为引用类型 内容存储于堆内存中 栈内存只存储了数组的引用指针 所以数组变量直接作为赋值值时只是将栈内存的地址指针赋值给了浅拷贝的接收变量, 
var arr = [1,2,3];
var arr1 = arr;  //这是普通的引用类型数组对象指针复制,即只是把栈内存的引用指针给你,arr和arr1两个指针指向同一个堆内存的地址,但是坏处就是一旦两个指针的其中一个去修改堆内存的元素内容,则也会影响到另一个指针复制的内容,会相互影响.
			
arr[2] = 5;
arr // [1,2,5]
arr1 //  [1,2,5]
//即原来arr指针指向的[1,2,3]引用数组改了,则新复制变量arr1也会跟着改,因为只是复制指针地址.	

//那么如何切断引用复制,改进: var arr1 = arr.slice();即可浅拷贝
//或者 var arr1 = arr.concat();也行浅拷贝
具体如何切断引用复制造成的影响?
    //第一种方法 ,plants.slice();方法返回的数组和原来的plants在堆内存各自互不影响的
    var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆'];
    var newArr = plants.slice(); //不传参 全切割并且返回一个全新数组浅拷贝,跟原来的plants完全没关系了,不是引用复制了.
   
    console.log(newArr); //['西红柿', '黄瓜', '芹菜', '豆角', '土豆'];
    newArr[2] = '西瓜';
    console.log(newArr); //["西红柿", "黄瓜", "西瓜", "豆角", "土豆"]
    

    //第二种方法,创建一个新数组对象,但不是深拷贝,完全自new数组新对象了,一个一个放几颗
     newArr = [];
    for (var i = 0, len = plants.length; i < len; i++) {
      newArr.push(plants[i]);
      
    }
    newArr[2] = '西瓜';
    console.log(newArr, plants); //newArr和 plants堆内存各自互互不影响
    //["西红柿", "黄瓜", "西瓜", "芹菜", "豆角", "土豆"]
    //["西红柿", "黄瓜", "芹菜", "豆角", "土豆"] 
slice有参使用代码案例: 浅拷贝一部分.
var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆'];

console.log(plants.slice());//如果不传参 默认切割整个数组;
//['西红柿', '黄瓜', '芹菜', '豆角', '土豆']

console.log(plants.slice(2)); //一个参数代表,从下标2开始到结尾全部都拷贝给我
// ['芹菜', '豆角', '土豆']

console.log(plants.slice(2, 4)); //一个参数代表,从下标2开始到下标4-1全部都拷贝给我.(不包括结束4下标)
// [ '芹菜', '豆角']

console.log(plants.slice(1, 5)); //1-5 ,从下标1开始到下标5-1
//  ['黄瓜', '芹菜', '豆角', '土豆']

//如果是负数的注意是从倒数第x个开始切割复制
console.log(plants.slice(-2, -4)); 
//失效的,因为数组是有序只能从左往右切割复制 而-2是在-4的右边,不能从右往左切割
//['西红柿'-5, '黄瓜'-4, '芹菜'-3, '豆角'-2, '土豆'-1] 

console.log(plants.slice(-4, -2)); //正确的,因为数组是有序只能从左往右切割复制
//['黄瓜'-4, '芹菜'-3]  , 从下标-4开始到下标-2-1.
参数
arr.slice([begin[, end]]) //begin 和end都是可选参数
如果不传参 默认切割整个数组
begin 可选
    提取起始处的索引(从 0 开始),从该索引开始提取原数组元素。
    如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2) 表示提取原数组中的倒数第二		个元素到最后一个元素(包含最后一个元素)。
    如果省略 begin,则 slice 从索引 0 开始。
    如果 begin 大于原数组的长度,则会返回空数组。

end 可选
    提取终止处的索引(从 0 开始),在该索引处结束提取原数组元素。slice 会提取原数组中索引从 begin 到 		end 的所有元素(包含 begin,但不包含 end)。
    slice(1,4) 会提取原数组中从第二个元素开始一直到第四个元素的所有元素 (索引为 1, 2, 3的元素)。
    如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。 slice(-2,-1) 表示抽取了原数组中			的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)。
    如果 end 被省略,则 slice 会一直提取到原数组末尾。
    如果 end 大于数组的长度,slice 也会一直提取到原数组末尾。

返回值
一个含有被提取元素的新数组。

8.concat(合并多个数组,返回一个新的数组对象[ ])

1.合并方法用于合并两个或多个数组,String也有concat但是String多用+号直接拼接.
2.此方法不会更改现有数组,而是返回一个新数组。

2.concat不写参数时可作为浅拷贝.即单独合并自己返回一个新自己数组对象.

var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆'];
var otherPlants = ['冬瓜', '韭菜']
var newPlants = plants.concat(otherPlants);

console.log(newPlants); 
//['西红柿', '黄瓜', '芹菜', '豆角', '土豆', '冬瓜', '韭菜']


参数
var newArray = oldArray.concat(value1[, value2[, ...[, valueN]]]);

valueN可选
数组和/或值,将被合并到一个新的数组中。
如果省略不写所有 valueN 参数,则 concat 会返回调用此方法的现存数组的一个浅拷贝。
返回值
一个合并后的新数组。

9.indexOf(通过元素找下标 )

方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。

indexof的原理(用for展示)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dz9MrzLI-1620234826839)(C:\Users\tuyue\AppData\Local\Temp\1615430975749.png)]

var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆','黄瓜'];

console.log(plants.indexOf('黄瓜')); 
//1

console.log(plants.indexOf('黄瓜',3));  //第二个数字参数是指,系统从数组第几个下标开始给你找,因为怕遇到一样内容的,因此这种可以缩小精确范围.
//5

console.log(plants.indexOf('大象')); 
//-1

参数
arr.indexOf(searchElement[, fromIndex])

searchElement
要查找的元素

fromIndex 可选
开始查找的位置。如果该索引值大于或等于数组长度,意味着不会在数组里查找,返回-1。如果参数中提供的索引值是一个负值,则将其作为数组末尾的一个抵消,即-1表示从最后一个元素开始查找,-2表示从倒数第二个元素开始查找 ,以此类推。 注意:如果参数中提供的索引值是一个负值,并不改变其查找顺序,查找顺序仍然是从前向后查询数组。如果抵消后的索引值仍小于0,则整个数组都将会被查询。其默认值为0.
返回值
首个被找到的元素在数组中的索引位置; 若没有找到则返回 -1

九.数组排序算法!!!

时间复杂度: 算法计算需要的时间成本.

排序的本质: 排好顺序 ,比较大小,互换位置. (都是从第一个数开始比)

1.冒泡排序

(每次两两对比,谁小个子谁往前,再继续两两对比)
(最次挑最大放最右边 然后踢掉, 然后再次循环len次每次再找最大即可)
(最后升序排,从小到大即可)

冒泡排序是一种比较简单的排序算法,这种算法是让越小或者越大的元素经由交换慢慢“浮”到数列的顶端,就像水里面的泡泡向上浮动一样,所以叫“冒泡排序”。 冒泡排序算法的原理 如下:

②冒泡排序的次数规律(死记):
元素的个数为arr.length:
1.总共需要外层for循环次数;length-1次。(因为循环一次就卡走一个最大元素,到最后两个元素循环比完就全部输出了,最后一次元素就就不用循环了,length-12、每一次内层for循环中剩余数据之间对转(对比)次数也是:n-1次  对比=对转
3、而内层for总共需要对比(对转)次数:①用元素个数n;n(n-1)/25*4/2=10.
                  
  1. 每次是都比较j和j+1的两两相邻的元素。如果第一个比第二个大,就交换他们两个。 (每一次都会把最大的数推到后面)

2.对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

  1. 针对所有的元素重复以上的步骤,除了最后一个.
  2. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nPPA0z0f-1620234826844)(D:/%E5%89%8D%E7%AB%AF%E8%B5%84%E6%96%99/js_20200713_224341/js%E7%AC%AC%E4%B8%83%E5%A4%A9%20%E6%95%B0%E7%BB%84%20sp/%E8%AF%BE%E4%BB%B6%E7%AC%94%E8%AE%B0/assets/1391679-20180618163321525-1936669878.gif)]

代码表现

var arr = [4,6,3,2,7,9,11,1];//n个数,两两相比,只需要比n-1次,即间隔有多少个.
var length = arr.length;
var temp;//中间的空瓶子middle
//记住i 和 j 都是指代下标,并不是具体数, 交换i 和 min其实是交换下标而已,具体的数是arr[i]或arr[j] 

for(var i = 0; i < length-1; i++) { //外层是计数器,决定排序次多少次能升序排序好,不用管先.
 //因为循环一次就卡走一个最大元素,到最后两个元素循环比完就全部输出了,最后一次元素就就不用循环了,length-1  
    
    // 内层决定每一次排都是怎么具体对转的,才把最大数排去最右边内外层,两层都是针对同一数组
    for(var j = 0; j< length - 1 - i; j++) {  
//为什么要length-1 ? 因为冒泡排序原理决定的,两两相比,len个数,只需要比len-1次,即间隔有多少个就比多少次.
//为什么还要-i?因为每次比完都一定会找到一个最大数去最右边,因此第i次找就能卡走排除几个不用再比的最高值数(PS:注意是从下标0开始代表第一次找)
//因此length - 1 - i代表实际每次只需对换比较length - 1 - i次.(同时i也是为了把已经比出来的最大值卡走)
//举例:length - 1 - i , 第一次排次数: 8-0-1  第二次排次数: 8-1-1 ..以此类推
        if (arr[j] > arr[j + 1]) {  //如果前一个j>后一个j+1,就两两互换位置,直到最大值去最右边.
            temp = arr[j];
            arr[j] = arr[j + 1]; 
            arr[j + 1] = temp; 
        }
    }
}
console.log(arr);  

2.选择排序

选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。

2、选择排序法;
int[] i={5,2,4,6,1};
选择排序是每次循环里找出最小的元素和前面的数据“对调位置”,直到放到最左边。
第一次循环:1,2,4,6,5
第二次循环:2,4,6,5
第三次循环:4,6,5
第四次循环:5,6
第五次循环:6
每次循环取出最右边的元素:1,2,4,5,6
选择排序的规律:元素的个数为n,总共需要循环n次,每次循环对调1次,对比n-1次。

3、选择排序;是每次内层循环里找出最小的元素值和前面的数据“对调位置”,直到把最小值放到最左边。(选择就是可以自己找出最小值去放到最左边)
冒泡排序;是每次内层循环都采用了“两两元素”比对大小然后相互对调的方法,直到把最大值放到最右边。(冒泡就是每次最大的泡泡先出去)
总体而言选择排序比冒泡排序效率高;efficient/effective

②选择排序的次数规律(死记):元素的个数为n;1、总共需要循环次数;n-1次。(因为循环一次就卡走一个最大元素,到最后两个元素循环比完就全部输出了就不用循环了,因此n-12、每一次循环中剩余数据之间对转(对比)次数;n-1次  对比=对转
                                            3、而总共需要对比(对转)次数;
              (简单方便易懂)                 用元素个数n;n(n-1)/25*4/2=10

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AB0V0G5W-1620234826849)(D:/%E5%89%8D%E7%AB%AF%E8%B5%84%E6%96%99/js_20200713_224341/js%E7%AC%AC%E4%B8%83%E5%A4%A9%20%E6%95%B0%E7%BB%84%20sp/%E8%AF%BE%E4%BB%B6%E7%AC%94%E8%AE%B0/assets/20190324234421659.gif)]

代码表现

var arr = [4,6,3,2,7,9,11,1];
var length = arr.length;
var minIndex, temp; 
for (var i = 0; i < length - 1; i++) { 
    minIndex = i;//把每次要拿去对换的数都看成是最小值的下标
    for (var j = i + 1; j < length; j++) { //j才是每次具体怎么对换
      if (arr[j] < arr[minIndex]) { //此时j=i+1  minIndex=i 即i+1<i比,即后面比最小的还小,则替代最小
          minIndex = j;  //发现更还小的数即arr[i+1]比arr[i]还小,即i下标不是min最小值,则换下标,即换容器j进入min代替成为最小值下标.但此时j是i+1
      }
    }
    temp = arr[i]; //因此要再用,中间盒子temp,让minIndex下标的盒子(此时是更小值j即i+1)和i下标的值互换容器,此时min最小值就是在当前的arr[i]中了.
    arr[i] = arr[minIndex];
    arr[minIndex] = temp;
}
	console.log(arr); 

3.插入排序

插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aaEbKQsZ-1620234826853)(D:/%E5%89%8D%E7%AB%AF%E8%B5%84%E6%96%99/js_20200713_224341/js%E7%AC%AC%E4%B8%83%E5%A4%A9%20%E6%95%B0%E7%BB%84%20sp/%E8%AF%BE%E4%BB%B6%E7%AC%94%E8%AE%B0/assets/1391679-20180618165919523-196396537.gif)]

代码表现

var arr = [4,6,3,2,7,9,11,1];
var length = arr.length;
for (var i = 1; i < length; i++) {
    var key = arr[i], j = i - 1;
    while (arr[j] > key) {
      arr[j + 1] = arr[j];
      j--;
    }
    arr[j + 1] = key;
  }
4.求一组数中的最大值和最小值,以及所在位置
//求一组数中的最大值和最小值,以及所在位置下标
    var arr = [1, 2, 3, 4, 5, 6, 7];
    var max = arr[0], min = arr[0], maxIdx = 0, minIdx = 0;
    for (var i = 0, len = arr.length; i < len; i++) {
      if (arr[i] >= max) {  //这里是选择排序,拿第i下标arr[i]去和arr[0].比大于他就把mx变为arr[i]
         //比他大就调转进maxIdx下标的容器去,max值就是arr[i],最后在此模式下循环个几次
        maxIdx = i; //这里是调换下标得出最大下标
        max = arr[i]; //这里是调换数值得出最大下标
      }
      if (arr[i] <= min) {
        minIdx = i;
        min = arr[i];
      }
    }

    console.log(max, min, maxIdx, minIdx);

十.数组引用类型深入

数组属于对象object的一种,从数据类型上隶属于 引用类型

非引用关系的基础类型 在进行直接赋值的时候 会对赋值变量(右边)对应栈内存中空间所存储的值 赋值 给 被赋值变量(左边) 
var str = '你好';
var str1 = str; //已经是把变量内部存储的具体值给你了,因此原来的str再变的时候就不关你的事了
str = 'hello';
str // 'hello'
str1 // '你好'

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LByvHuBL-1620234826854)(D:/%E5%89%8D%E7%AB%AF%E8%B5%84%E6%96%99/js_20200713_224341/js%E7%AC%AC%E5%85%AB%E5%A4%A9%20%E6%95%B0%E7%BB%84%E4%B8%8E%E5%AD%97%E7%AC%A6%E4%B8%B2%20sp/%E8%AF%BE%E4%BB%B6%E7%AC%94%E8%AE%B0/assets/image-20200721142849500.png)]

而引用类型进行直接变量赋值操作时 因为数组为引用类型 内容存储于堆内存中 栈内存只存储了数组的引用指针 所以数组变量直接作为赋值值时只是将栈内存的地址指针赋值给了浅拷贝的接收变量, 
var arr = [1,2,3];
var arr1 = arr;  //这是浅拷贝的引用类型数组对象指针复制,即只是把栈内存的引用指针给你,arr和arr1两个指针同时				 //指向堆内存的地址,但是一旦原来的指针指向的堆内存内容改了,则也会影响到指针复制的新接收变量
			 //即原来arr指针指向的[1,2,3]引用数组改了,则新复制变量arr1也会跟着改,因为只是复制指针地址.	
arr[2] = 5;
arr // [1,2,5]
arr1 //  [1,2,5]  会跟着arr一起改.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e9xMO2Db-1620234826856)(D:/%E5%89%8D%E7%AB%AF%E8%B5%84%E6%96%99/js_20200713_224341/js%E7%AC%AC%E5%85%AB%E5%A4%A9%20%E6%95%B0%E7%BB%84%E4%B8%8E%E5%AD%97%E7%AC%A6%E4%B8%B2%20sp/%E8%AF%BE%E4%BB%B6%E7%AC%94%E8%AE%B0/assets/image-20200721214028443.png)]

因此我们为了切断这种引用关系 我们可以选择进行 按顺序给新数组push或者赋值 或者使用slice()进行浅拷贝 后续会学习深拷贝

var arr = [1,2,3];
var arr1;
for(var i = 0, len = arr.length; i < len; i++) {
 arr1[i] = arr[i];
 // arr1.push(arr[i]);
}

arr1 = arr.slice(); //浅拷贝

数组基本作业:

求一组数中的所有数的和和平均值
求一组数中的最大值和最小值,以及所在位置
将字符串数组用|或其他符号分割
要求将数组中的0项去掉,将不为0的值存入一个新的数组,生成新的数组//去重
查找数组[1,2,3,4,1,2,3,4,2,3,1,1,0]中所有值为1的项的下标 输出为新数组
翻转数组
冒泡排序,从小到大 (上面有)

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>0721作业</title>
</head>

<body>


  <script>
    /*
    求一组数中的所有数的和和平均值
    求一组数中的最大值和最小值,以及所在位置
    将字符串数组用|或其他符号分割
    要求将数组中的0项去掉,将不为0的值存入一个新的数组,生成新的数组
    查找数组[1,2,3,4,1,2,3,4,2,3,1,1,0]中所有值为1的项的下标 输出为新数组
    翻转数组

    */


    //   求一组数中的所有数的和和平均值

    var arr = [1, 2, 3, 4, 5, 6, 7];
    var count = 0, avg = 0;

    for (var i = 0, len = arr.length; i < len; i++) {
      count += arr[i];
    }

    avg = count / len;
    console.log(count, len);



    //求一组数中的最大值和最小值,以及所在位置下标
    var arr = [1, 2, 3, 4, 5, 6, 7];
    var max_value = arr[0], //假设数组第一个值为最大值.
    min_value = arr[0], //假设数字第一个值为最小值.
    maxIdx = 0,
    minIdx = 0;
    var len = arr.length;

    for (var i = 0; i < len; i++) {
      if (arr[i] >= max_value) {  //第二次实际这里间接变为比较:arr[i+1] >= arr[i];
        //遍历数组,拿第i个下标arr[i]去和arr[0].一旦有比假设最大值大的数则下标和数组都分别更新为max_value 和  maxIdx 
        //然后一直循环下去,只要下一次比这一次大的,就把下一次更新为max_value 和  maxIdx 即可,
        //直到数组遍历完,看max_value 和  maxIdx 最终更新到哪个值,那个值就是真正的最大值和最大值下标.
        maxIdx = i;
         //这里每次是调换下标更新为最大下标
        max_value = arr[i]; 
        //这里每次是调换数值更新为得出当前最大值,然后与此同时也就更新在最上面的max_value声明中.然后循环中的max_value就会同步.
        //切记:这种只是更新max_value 和  maxIdx 假设最大值和其下标 套给数组的某个数的表面称号而已.
        //实际并不会改变数组的位置和整体排序. 下面的最小值同理的
      }

      if (arr[i] <= min_value) {
        minIdx = i;
        min_value = arr[i];
      }
    }

    console.log(max_value, min_value, maxIdx, minIdx); //7 1 6 0



    // 将字符串数组用|或其他符号拼接成字符串
    var strArr = ['大', '家', '好'];//join方法.拼接为一个字符串
    console.log(strArr.join('|')); //大|家|好


    var str = '你猜猜我是谁'; //裂开方法
    console.log(str.split(''));//'你' '猜' '猜' '我' '是' '谁'


    //要求将数组中的 0 项去掉,将不为0的值存入一个新的数组,生成新的数组
    arr = [0, 2, 3, 54, 56, 1, 0, 6, 2];
    var newArr = [];//new 一个新数组
    var len = arr.length;
    for (var i = 0; i < len; i++) { //遍历
      if (arr[i] !== 0) {          //如果遍历时,找到不为0的值,
        newArr.push(arr[i]);       //则把不为0的值push存入新数组.
      }
    }
    console.log(newArr);


    //查找数组[1,2,3,4,1,2,3,4,2,3,1,1,0]中所有值为1的项的下标 输出为新数组
    arr = [0, 2, 3, 1, 54, 56, 1, 0, 6, 2];
    var newArr = [];//new 一个新数组
    var len = arr.length;
    for (var i = 0; i < len; i++) {
      if (arr[i] === 1) {     //如果遍历时,找到为1的值,
        newArr.push(i);       //!!!则把不为0的值的下标push存入新数组中
      }
    }

    console.log(newArr);



    //翻转数组 
    arr = [0, 2, false, 1, 54, 56, 1, 0, 6, 'haha']; //[2,6,0,1,56,54,1,3,2,0]
    newArr = [];
    len = arr.length
    var temp;
    for (var i = 0; i < len / 2; i++) { //调转长度一半次即可
      temp = arr[i];
      arr[i] = arr[len - 1 - i];  //arr[0] = arr[10 - 1 - 0]; 第一个和倒一个互换即可,最终循环五次即可全部反转.
      arr[len - 1 - i] = temp;  
    }

    console.log(arr); //["haha", 6, 0, 1, 56, 54, 1, false, 2, 0].



    /*
      一、看数组 观察变化找规律
      初始 ['a','b','c','d','e']
      第一次 ['d','e','a','b','c']
      第二次 ['b','c','d','e','a']
      第三次 ['e','a','b','c','d']

      每一次下标进位2

    */
    var arr = ['a', 'b', 'c', 'd', 'e'];
    len = len = arr.length; //5
    var resultArr = [];
    for (var j = 1; j <= 16; j++) {
      resultArr = [];
      for (var i = 0; i < len; i++) {
        resultArr[(i + 2) % len] = arr[i];
      }
      arr = resultArr;
      console.log(resultArr + '第' + j + '次');
    }






    /* 余数规律
      0%5 0
      1%5 1
      2%5 2
      3%5 3
      4%5 4
      5%5 0
      6%5 1
      7%5 2
      8%5 3
      9%5 4
     10%5 0
    */
  </script>
</body>

</html>

数组深入作业:

一、看数组 观察变化找规律
初始 ['a','b','c','d','e'] 
第一次 ['d','e','a','b','c']
第二次 ['b','c','d','e','a']
第三次 ['e','a','b','c','d']
...
请问第五次 第十五次数组是如何?

二、抽茧剥丝
var arr = ['鸡腿',101,'3','奥利奥',9,false,'33a',1.333,'巧克力'];
求数组中所有类型为number的整数之和

三.数组替换switch实现根据0-6打印星期一到星期日
.
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>找规律</title>
</head>

<body>


  <script>
    /*
      一、看数组 观察变化找规律
      初始 ['a','b','c','d','e']
      第一次 ['d','e','a','b','c']
      第二次 ['b','c','d','e','a']
      第三次 ['e','a','b','c','d']
      ...

      规律:
        每一次变幻相比上一次都是每位值进行了+2位移 超出范围的从0开始 0 1 2 3 4 5 => 4 5 0 1 2 3
    */


    var originArr = ['a', 'b', 'c', 'd', 'e'], resultArr
    for (var i = 1; i <= 15; i++) {
      resultArr = [];
      for (var j = 0, originLen = originArr.length; j < originLen; j++) {
        resultArr[(j + 2) % originLen] = originArr[j];
      }
      originArr = resultArr;
      console.log('第' + (String(i)[1] && i || '0' + i) + '次结果为: [' + resultArr + ']');
    }


    //短路技巧
    var x = 1;
    console.log(String(x)[1] && x || '0' + x)
  </script>
</body>

</html>
.<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>抽茧剥丝</title>
</head>

<body>


  <script>
    /*
      var arr = ['鸡腿',101,'3','奥利奥',9,false,'33a',1.333,'巧克力'];
      求数组中所有类型为number的整数之和

      类型为number的整数
      条件 
        1. 类型为number
        2. 整数
    */


    var arr = ['鸡腿', 101, '3', '奥利奥', 9, false, '33a', 1.333, '巧克力'];
    var count = 0;
    for (var i = 0, len = arr.length; i < len; i++) {
      if (~~arr[i] === arr[i]) {
        count += arr[i];
      }
    }
    // console.log(count);



    /*
      var arr = ['鸡腿',101,'3','奥利奥',9,false,'33a',1.333,'巧克力'];
      求数组中所有 类型为number的整数 之和

      类型为number的整数
      条件
        1. 类型为number
        2. 整数
    */

    var arr = ['鸡腿', 101, '3', '奥利奥', 9, false, '33a', 1.333, '巧克力'];
    var sum = 0;

    // for (var i = 0, len = arr.length; i < len; i++) {
    //   if (typeof arr[i] === 'number' && arr[i] % 1 === 0) {
    //     sum += arr[i];
    //   }
    // }

    for (var i = 0, len = arr.length; i < len; i++) {
      if (~~(arr[i]) === arr[i]) {
        sum += arr[i];
      }
    }

    // console.log(sum);

    for (var i = 1; i <= 20; i++) {
      // 10  '10' 
      console.log(String(i)[1] && String(i) || '0' + i);
    }


  </script>
</body>

</html>
作业三.自己完善一下
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>数组思考</title>
</head>

<body>
  <script>

    // switch 打印星期几 0为星期日 1 - 6分别对应星期一到星期六

    var day = 0;
    switch (day) {
      case 0:
        console.log('星期日');
        break;
      case 1:
        console.log('星期一');
        break;
      case 2:
        console.log('星期二');
        break;
    }
 
    //上面的switch太累赘了,因此可以用数组下标映射去代替case的0 1 2...
    //数组映射 ---->用空间换时间 分支值或者可能性非常多并且有规律的时候
    var weekDay = ['日', '一', '二', '三', '四', '五', '六'];
    console.log('星期' + weekDay[day]);

  </script>
</body>

</html>
  var arr = ['鸡腿',101,'3','奥利奥',9,false,'33a',1.333,'巧克力'];
  求数组中所有 类型为number的整数 之和

  类型为number的整数
  条件
    1. 类型为number
    2. 整数
*/

var arr = ['鸡腿', 101, '3', '奥利奥', 9, false, '33a', 1.333, '巧克力'];
var sum = 0;

// for (var i = 0, len = arr.length; i < len; i++) {
//   if (typeof arr[i] === 'number' && arr[i] % 1 === 0) {
//     sum += arr[i];
//   }
// }

for (var i = 0, len = arr.length; i < len; i++) {
  if (~~(arr[i]) === arr[i]) {
    sum += arr[i];
  }
}

// console.log(sum);

for (var i = 1; i <= 20; i++) {
  // 10  '10' 
  console.log(String(i)[1] && String(i) || '0' + i);
}
```
作业三.自己完善一下
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>数组思考</title>
</head>

<body>
  <script>

    // switch 打印星期几 0为星期日 1 - 6分别对应星期一到星期六

    var day = 0;
    switch (day) {
      case 0:
        console.log('星期日');
        break;
      case 1:
        console.log('星期一');
        break;
      case 2:
        console.log('星期二');
        break;
    }
 
    //上面的switch太累赘了,因此可以用数组下标映射去代替case的0 1 2...
    //数组映射 ---->用空间换时间 分支值或者可能性非常多并且有规律的时候
    var weekDay = ['日', '一', '二', '三', '四', '五', '六'];
    console.log('星期' + weekDay[day]);

  </script>
</body>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值