数据结构和算法(一)之数组结构

数据结构和算法(一)之数组结构

一.数组的基本使用

创建和初始化数组

  • 用JavaScript声明、创建和初始化数组很简单,如下:

    //创建和初始化数组
    let daysOfWeek = new Array();
    let daysOfWeek = new Array(7);
    let daysOfWeek = new Array('Sunday','Moday','Tuesday','Wednesday','Thursday','Friday','Saturday');
    
  • 代码解析:

    • 使用new关键字,就能简单地声明并初始化一个数组
    • 用这种方式,还可以创建一个指定长度的数组
    • 另外,也可以直接将数组元素作为参数传递给它的构造器
    • new创建数组并不是最好的方式。如果你想在JavaScript中创建一个数组,只用中括号([])的形式就行了
  • 使用中括号([])创建数组:

    let daysOfWeek = new Array('Sunday','Moday','Tuesday','Wednesday','Thursday','Friday','Saturday');
    

数组长度和遍历数组

  • 如果我们希望获得数组的长度,有一个length属性

    //获取数组的长度
    alert(daysOfWeek.length)
    
  • 也可以通过下标值来遍历数组:

    //普通for方法遍历数组
    for(let i = 0;i<daysOfWeek.length;i++){
    	alert(daysOfWeek[i])
    }
    
    //通过foreach遍历数组
    daysOfWeek.forEach(function (value){
        alert(value)
    })
    
  • 我们来做个练习:

    • 求菲波那切数列的前20个数字,并且放在数组中。

    • 菲波那切数列数列第一个数字是1,第二个数字也是1,第三项是前两项的和

      //求菲波那切数列的前28个数字
      let fibonac = [];
      fibonac[0] = 1;
      fibonac[1] = 1;
      
      for(let i = 2;i < 20;i++){
          fibonac[i] = fibonac[i-1] + fibonac[i - 2];
      }
      alert(fibonac);
      

二.数组的常见操作

数组中常见的操作有:添加元素、删除元素、修改元素、获取元素

添加元素

  • JavaScript中,进行上述操作都比较简单,因为语言本身都已经封装好了这些特性。

  • 假如我们有一个数组:numbers,初始化0~9

    // 初始化一个数组
    let numbers = [0,1,2,3,4,5,6,7,8,9];
    
  • 添加一个元素到数组的最后位置:

    // 添加一个元素到数组的最后位置
    // 方式一:
    numbers[numbers.length] = 10;
    
    // 方式二:
    numbers.push(11);
    numbers.push(12,13)
    
    alert(numbers);
    
  • 在数组首位插入一个元素:

    // 在数组首位插入一个元素
    for(let i = numbers.length;i > 0;i--){
    	numbers[i] = numbers[i-1]
    }
    numbers[0] = -1
    alert(numbers) // -1,0,1,2,3,4,5,6,7,8,9,10,11,12,13
    
  • 上面代码实现的原理是怎么样的呢?
    在这里插入图片描述

  • 考虑上面代码实现的性能怎样呢?

    • 性能并不算非常高
    • 这也是数组和链表相对比的一个劣势:在中间位置插入元素的效率比链表低
  • 当然,我们在数组首位插入数据可以直接使用unshift方法

    // 通过unshift在首位插入数据
    numbers.unshift(-2);
    numbers.unshift(-4,-3);
    alert(numbers) // -4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13
    

删除元素

  • 如果希望删除数组最后的元素,可以使用pop()方法

    // 删除最后的元素
    numbers.pop()
    alert(numbers) //-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12
    
  • 如果我们希望移除的首位元素:

    // 删除首位的元素
    for(let i = 0;i < numbers.length;i++){
    	numbers[i] = numbers[i+1]
    }
    numbers.pop();
    alert(numbers); //-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13
    
  • 当然,我们可以直接使用shift方式来实现:

    numbers.shift()
    alert(numbers)
    

任意位置

  • 任意位置?

    • 前面我们学习的主要是在数组的开头和结尾处添加和删除数据
    • 那如果我们希望在数组的中间位置进行一些操作应该怎么办呢?
  • 一方面,我们可以自己封装这样的函数,但JS已经给我们提供了一个splice方法

  • 通过splice删除数据

    // 删除指定位置的几个元素
    numbers.splice(5,3);
    alert(numbers); // -4,-3,-2,-1,0,4,5,6,7,8,9,10,11,12,13
    
  • 代码解析:

    • 上面的代码会删除索引为5,6,7位置的元素。
    • 第一个参数表示 索引起始的位置为5(其实是第6个元素,因为索引从0开始的),删除3个元素。
  • 如果我们希望使用splice来插入数据呢?

    // 插入指定位置元素
    numbers.splice(5,3,3,2,1);
    alert(numbers); //-4,-3,-2,-1,0,3,2,1,4,5,6,7,8,9,10,11,12,13
    
  • 代码解析:

    • 上面的代码会从索引5的位置开始修改数据,修改多少个呢?第二个参数来决定的。
    • 第一个参数依然是索引的位置为5(第六个位置)
    • 第二个参数是要将数组中多少个元素给替换掉,我们这里是3个(也可以使用3个元素来替换2个,可以自己尝试一下)
    • 后面跟着的就是要替换的元素。

三.数组的其他操作

JavaScript中添加了很多方便操作数据的方法

常见方法

  • 我们先对常见的方法简单来看一下

    方法名方法描述
    concat连接2个或更多数组,并返回结果
    every对数组中的每一项运行给定函数,如果该行苏对每一项都返回ture,则返回ture,否则返回false
    filter对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组
    forEach对数组中的每一项运行给定函数。这个方法没有返回值
    join将所有的数组元素连接成一个字符串
    indexOf返回第一个与给定参数相等的数组元素的索引,没有找到则返回-1
    lastIndexOf返回在数组中搜索到的与给定参数相等的元素的索引里最大的值
    map对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组
    reverse颠倒数组中元素的顺序,原先第一个元素现在变成最后一个,同样原先的最后一个元素变成了现在的第一个
    slice传入索引值,将数组里对应索引范围内的元素作为新元素返回
    some对数组中的每一项运行给定函数,如果任一项返回true,则结果为true,并且迭代结束
    sort对照字母表顺序组排序,支持传入指定排序方法的函数作为参数
    toString将数组作为字符串返回
    valueOftoString类似,将数组作为字符串返回

数组合并

  • 数组的合并非常简单,使用concat即可(也可以直接+进行合并)

    // 数组的合并
    let nums1 = [1,2,3]
    let nums2 = [100,200,300]
    let newNums = nums1.concat(nums2)
    alert(newNums) // 1,2,3,100,200,300
    
    newNums = nums1 + nums2
    alert(newNums) // 1,2,3,100,200,300
    

迭代方法

  • 为了方便操作数组,JS提供了很多迭代器方法:

  • every()方法
    • every()方法是将数组中每一个元素传入到一个函数中,该函数返回true/false.

    • 如果函数中每一个元素都返回true,有一个为false,那么结果为false

    • 练习:判断一组元素中是否都包含某一个字符
      // 定义数组
      let names = ["abc","cb","mba","dna"]
      
      // 判断数组的元素是否都包含a字符
      let flag = names.every(function(t){
      	return t.indexOf('a') != -1
      })
      alert(flag)
      
  • some()方法
    • some()方法是将数组中每一个元素传入到一个函数中,该函数返回true/false

    • 但是和every不同的是,一旦有一次函数返回true,那么迭代就会结束,并且结果为true

    • 练习:
    // 定义数组
    let names = ["abc","cb","mba","dna"]
    
    // 判断数组中是否含有a字符的字符
    let flag = names.some(function(t){
      alert(t);
      return t.indexOf("a") != -1;
    })
    alert(flag)
    
    
  • forEach()方法
    • forEach()方法仅仅是一种快速迭代数组的方式而已

    • 该方法不需要返回值

    • 使用
      // 定义数组
      let names = ["abc","cb","mba","dna"];
      
      // forEach的使用
      names.forEach(function(t){
      		alert(t)
      })
      
  • filter()方法
    • filter()方法是一种过滤的函数

    • 首先会遍历数组中每一个元素传入到函数中

    • 函数的结果返回true,那么这个元素会被添加到最新的数组中,返回false,则忽略该元素。

    • 最终会形成一个新的数组,该数组就是filter()方法的返回值

    • 练习:
        // 定义数组
        let names = ["abc","cb","mba","dna"]
        
        // 获取names中所有包含‘a’字符的元素
        let newNames = names.filter(function (t){
          return t.indexOf("a") !=-1
        })
        alert(newNames)
      
  • map()方法
    • map()方法提供的是一种映射函数

    • 首先会遍历数组中每一个元素传入到函数中

    • 元素会经过函数中的指令进行各种变换,生成新的元素,并且将新的元素,并且将新的元素返回

    • 最终会将返回的所有元素形成一个新的数组,改数组就是map()方法的返回值

    • 练习:
        // 定义数组
        let names = ["abc","cb","mba","dna"]
        
        // 在names中所有的元素后面拼接-abc
        let newNames = names.map(function(t){
        	return t + "-abc"
        })
        alert(newNames)
      

reduce方法

  • 我们单独拿出reduce方法,因为这个方法相对来说难理解一点

  • 首先,我们来看这个方法需要的参数:

    arr.reduce(callback[,initialValue])
    
  • 参数

    • callback(一个在数组中每一项上调用回调的函数,接受四个函数:)
      • previousValue(上一次调用回调函数时的返回值,或者初始值)
      • currentValue(当前正在处理的数组元素)
      • currentIndex(当前正在处理的数组元素下标)
      • array(调用reduce()方法的数组)
    • initialValue(可选的初始值。作为第一次调用回调函数时传给previousValue的值)
  • 有些晦涩难懂,我们直接看例子

    • 求一个数字的累加和

    • 使用for实现:

      // 定义数组
      let numbers = [1,2,3,4]
      
      // for实现累加
      let total = 0
      for(let i = 0;i<numbers.length;i++){
      	total += numbers[i]
      }
      alert(total) // 10
      
    • 使用forEach简化for循环

      • 相对于for循环,forEach更符合我们的思维(遍历数组中的元素)

        // 使用forEach
        let total = 0
        numbers.forEach(function(t){
        	total += t
        })
        alert(total)
        
    • 使用reduce方法实现

      // 使用reduce方法
      let total = numbers.reduce(function(pre,cur){
      	return pre + cur
      })
      alert(total)
      

      代码解析:

      • pre中每次传入的参数是不固定的,而是上次执行函数时的结果保存在了pre中
      • 第一次执行时,pre为0,cur为1
      • 第二次执行时,pre为1(0+1,上次函数执行的结果),cur为2
      • 第三次执行时,pre为3(1+2,上次函数执行的结果),cur为3
      • 第四次执行时,pre为6(3+3,上次函数执行的结果),cur为4
      • 当cur为4时,数组中的元素遍历完了,就直接将第四次的结果,作为reduce函数的返回值进行返回。
    • 似乎和forEach比较没有太大的优势呢?

      • 通过这个代码你会发现,你不需要在调用函数前先定义一个变量,只需要一个变量来接受方法最终即可。
      • 但是这就是优势吗?不是,优势在于reduce方法有返回值,而forEach没有。
      • 这算什么优势吗?如果reduce方法有返回值,那么reduce方法本身就可以作为参数直接传递给另外一个需要reduce返回值得作为参数的函数。而forEach中你只能先将每次函数的结果保存在一个变量,最后再将变量传入到参数中。
      • 没错,这就是最近非常流行的函数式编程。也是为了几乎每个可以使用函数式编程的语言都有reduce这个方法的原因。
      • 关于函数式编程,不再本次课程的讨论之中,只是看到了这个函数,给大家延伸了一下而已。
    • initialValue还需要讲吗?

      • 其实就是第一次执行reduce中的函数时,pre的值。
      • 因为默认pre第一次执行时为0.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yige001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值