程序员的知识教程库

网站首页 > 教程分享 正文

JavaScript 基础之数组(javascript数组操作)

henian88 2024-10-01 10:47:38 教程分享 7 ℃ 0 评论

本章目标

  • 掌握数组的定义和使用
  • 掌握循环数组的方式
  • 掌握获取数组中元素个数的方法

本章任务

  • 能够计算班级所有学生的总成绩和平均成绩
  • 能够求数组中的最大值
  • 能够对数组排序

数组

为什么要学习数组


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

数组的概念


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

数组的定义


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


// 定义一个空的数组,数组的字面量
let arr = [];

// 定义一个数组,存储5个学生的姓名
let names = ['刘备', '关羽', '赵云', '诸葛亮', '曹操'];

// 定义了一个数组,存储5个学生的成绩
let scores = [60, 89, 100, 55, 70];


数组存值


如果在给学生录入成绩的时候,输入错误,我们还可以更改学生的成绩。


数组中的数据使用索引(下标)管理,数组中的每一个数据都有一个序号(索引),但是要记住数组中的序号(索引)是从0开始的。


  • 语法
// 索引从0开始
数组名称[索引] = 新值;
  • 示例
let scores = [59, 70, 10];

// 修改第一个数据
scores[0] = 65;
// 修改最后一个数据
scores[2] = 60;

console.log(scores);


上面代码中,数组只有3个元素,最大的索引值为2。

如果班级里有5个学生的话,后两个学生的成绩该如何录入呢?


let scores = [59, 70, 10];
// 录入第4个和第5个学生的成绩
scores[3] = 99;
scores[4] = 100;

console.log(scores);

获取数组元素


学生的成绩我们已经可以存储到数组中了,那如何把存储到数据中的成绩获取出来计算总成绩呢?


把数据存储在数组里面,是为了将来能使用的,所以要从里面把数据取出来。数据取值同样使用索引取值


  • 语法
数组名称[下标]
// 下标又称为索引,数组的下标是从0开始的


  • 示例
let scores = [59, 70, 10];

// 获取第一个学生
console.log(scores[0]);

// 计算总成绩
let sum = socres[0] + scores[1] + scores[2];

把 数组名称[索引]格式当成一个变量使用


在上面代码的基础上,如果打印索引是3的元素,结果会是什么呢?


let scores = [59, 70, 10];
console.log(scores[3]); // undefined

可以发现,打印数组中不存在的元素,和使用定义未赋值的变量效果是一样的,输出的结果都是 undefined。

遍历数组


在获取数组元素中求总成绩的时候,我们把数组中的元素一个一个取出来累加求和,之前的数组中只有3个人的成绩,如果数组中存储的是30个人或者300个人的成绩,这个时候该如何求总成绩呢?


这个时候可以使用循环的方式来解决。


let scores = [60, 59, 80, 100];
let sum = 0;
// 在遍历数组的时候经常使用 for 循环
for (let i = 0; i <= 3; i++) {
	sum += scores[i];
}
console.log(sum);


注意:数组中总共有4个元素,在遍历数组的时候索引从0开始,循环到数组的最大索引。此时的最大索引值是3。


我们求一个班的成绩可以这样实现,只要找到数组的最大索引就可以遍历数组。如果要求每一个班级的学生总成绩该如何做呢?不同班级的人数是不同的。


我们只需要知道数组的长度(数组中的元素个数)就可以计算数组中的最大索引


  • 获取数组的元素个数
    • 数组名称.length
let scores = [60, 59, 80, 100];
console.log(arr.length); // 4


获取到数组长度 数组.length,数组中的大索引值(最后一个索引值),只需要使用 数组.length - 1就可以获得,因为数组的索引是从0开始的。


let scores = [60, 59, 80, 100];
let sum = 0;
// 在遍历数组的时候经常使用 for 循环
for (let i = 0; i <= scores.length - 1; i++) {
	sum += scores[i];
}
console.log(sum);

这里的条件还可以改成 i < scores.length

let scores = [60, 59, 80, 100];
let sum = 0;
// 在遍历数组的时候经常使用 for 循环
for (let i = 0; i < scores.length; i++) {
	sum += scores[i];
}
console.log(sum);

清空数组

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

arr = [];
// or
arr.length = 0;


案例


  • 求一个数组中所有数字的总和和平均值
  • 求数组中所有数字的最大值
  • 求数组中最大值的索引
  • 通过 prompt 让用户输出5个学生的成绩,存储到数组中,并求总成绩和平均成绩

冒泡排序


根据如图所示,我们要排序一组数,首先可以比较相邻的两个数,如果第一个数大于第二个数则交换位置,这样两两比较的之后,经过第一轮(这组数中两两比较结束)就可以获得这组数中的最大的那一个。而两两比较的次数总共需要 length - 1次。


假设数组为 [4, 3, 2, 1],第一轮比较过程如下:

  • 4 3 2 1 > 3 4 2 1
  • 3 4 2 1 > 3 2 4 1
  • 3 2 4 1 > 3 2 1 4


我们把上面的这段话翻译成代码的形式,如下:

let arr = [10, 20, 30, 50];

// 循环数组,进行两两比较
for (let j = 0; j < arr.length - 1; j++) {
  // 两两比较,把大的数往后移动
  if (arr[j] > arr[j + 1]) {
    // 交换两个数的位置
    let tmp = arr[j];
    arr[j] = arr[j + 1];
    arr[j + 1] = tmp;
  }
}

console.log(arr);


刚刚比较结束之后只找到到最大的数,排序并没有结束,还需要重复执行上面的代码,再找到倒数第二大的值、倒数第三大的值。如果数组中有 n 数,这个过程需要重复 n - 1 次。


假设数组为 [4, 3, 2, 1],第一轮比较过程如下:

  • 4 3 2 1 > 3 4 2 1
  • 3 4 2 1 > 3 2 4 1
  • 3 2 4 1 > 3 2 1 4


上述是第一轮的过程,第二轮

  • 3 2 1 4 > 2 3 1 4
  • 2 3 1 4 > 2 1 3 4


第三轮

  • 2 1 3 4 > 1 2 3 4


如果数组中有4个数字,总共需要三轮循环。


代码实现如下:


let arr = [10, 20, 30, 50];

// 控制比较的轮数
for (let i = 0; i < arr.length - 1; i++) {

  // 进行两两比较的循环
  for (let j = 0; j < arr.length - 1; j++) {
    // 两两比较,把大的数往后移动
    if (arr[j] > arr[j + 1]) {
      // 交换两个数的位置
      let tmp = arr[j];
      arr[j] = arr[j + 1];
      arr[j + 1] = tmp;
    }
  }
}

console.log(arr);


到此数组排序结束,但是这个内层循环,每轮比较的过程中都会循环 length - 1次,刚进过刚刚的拆解分析,我们可以得到如下结论:


  • 第一轮,找最大值,两两比较次数 length - 1
  • 第二乱,找倒数第二大的数(最大值已经确认),两两比较次数 length - 2
  • 第三轮,找倒数第三大的数(倒数第一、二大的数已经确认),两两比较次数 length - 3


对内层循环进行优化,arr.length - i - 1


let arr = [10, 20, 30, 50];

// 控制比较的轮数
for (let i = 0; i < arr.length - 1; i++) {
  // 进行两两比较的循环
  for (let j = 0; j < arr.length i - 1; j++) {
    // 两两比较,把大的数往后移动
    if (arr[j] > arr[j + 1]) {
      // 交换两个数的位置
      let tmp = arr[j];
      arr[j] = arr[j + 1];
      arr[j + 1] = tmp;
    }
  }
}


对外层循环进行优化,我们之前使用的是一组特殊的数字 [4, 3, 2, 1],这组数就需要把每一轮的循环执行完,才能排序结束。


如果待排序的一组数是 [ 4, 1, 2, 3 ],这组数只需要一轮循环即可排序完成,还有可能是 [ 4, 3, 1, 2]。总之根据带排序的数组,外层循环有可能不需要完全循环完毕。


那外层循环多少次呢?这个不好确定。这里我们使用一个小技巧来优化外层循环。

如果内层循环中发生了交换,也就是排序还没有结束,这个时候外层循环要继续,如果某一轮循环中内层循环中不再交换两两元素的位置,我们就可以确认此时排序已经结束,跟着这个特点,我们来对代码进行优化。


let arr = [10, 20, 30, 50];

// 控制比较的轮数
for (let i = 0; i < arr.length - 1; i++) {
  // 每一轮开始之前,假设排序结束
  let flag = true;

  // 进行两两比较的循环
  for (let j = 0; j < arr.length - 1 - i; j++) {
    // 两两比较,把大的数往后移动
    if (arr[j] > arr[j + 1]) {
      // 交换两个数的位置
      let tmp = arr[j];
      arr[j] = arr[j + 1];
      arr[j + 1] = tmp;

      // 如果发生两两交换,则排序没有结束
      flag = false;
    }
  }

  // 如果排序结束,跳出外层循环
  if (flag) {
    break;
  }
}

console.log(arr);


参考:

  • https://github.com/TonyLuo/Article
  • https://algorithm-visualizer.org/brute-force/bubble-sort


补充:数组的构造函数


数组在 JavaScript 中还可以使用另一种方式创建,这个方式我们称为 : 构造函数


// 使用 构造函数 创建数组
let arr = new Array();
// 存储数据
arr[0] = 10;
arr[1] = 20;
console.log(arr);


也可以在创建的同时存储数据


let arr = new Array(10,20);
console.log(arr);


但是要注意,如果只有一个数据,不要使用这个方式存储数据


let arr = new Array(10);
console.log(arr); // 输出 [empty × 10]


这是因为,如果只给一个数字构造函数,它会认为你想要设置数组的长度,而不是要把数据存储在数组中。所以不能使用这个方式存储一个数字数据。如果非要存一个数据,使用别的方式存储。

作业

  • 求数组中元素最小值
    • 假设数组中的第一个元素是最小值
  • 翻转数组
    • 实现效果
      • 假设数组为 ['a', 'b', 'c', 'd']
      • 输出结果 ['d', 'c', 'b', 'a']
    • 实现思路
      • 倒序遍历原数组,初始值i = arr.length - 1,条件 i >= 0,i--
      • 给新数组中的每一个元素赋值,可以通过 length 属性作为索引
  • 将字符串数组用 | 或其他符号分割成字符串
    • 实现效果
      • 假设数组为 ['a', 'b', 'c', 'd']
      • 输出结果 a|b|c|d
    • 实现思路
      • 先取出数组中的第一个元素存储到变量 s 中
      • 从数组中的第二个元素开始遍历,在遍历到的元素前拼接分隔符,追加到变量s中
      • s += '|' + arr[i]
  • 将1-100中3的倍数放入到一个数组中
  • 仿 siri 项目中实现求和的功能
    • 当输入1进行求和的时候,首先让用户输入,他要计算多少个数字的和
    • 再依次输入每个数字
    • 最后打印求和的结果

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表