JS 数据结构与算法——数组/列表

JavaScript 数据结构与算法中的数组(Array)和列表(List)是两种基本的数据结构,它们在存储和操作数据时起着重要的作用。数组和列表都支持常见的操作,如插入、删除、查找和遍历等,但它们在内存分配、插入删除操作的效率等方面有所不同。了解数组和列表的特性以及它们的适用场景,对于编写高效的 JavaScript 程序以及理解复杂的算法和数据结构都至关重要。

数组

数组的标准定义是: 一个存储元素的线性集合(collection),元素可以通过索引来任意存取,索引通常是数字,用来计算元素之间存储位置的偏移量。

JavaScript 数组用于在单一变量中存储多个值。

  1. 使用数组文本是创建 JavaScript 数组最简单的方法。(推荐)
js 复制代码
var array-name = [item1, item2, ...];

var cars = ["Saab", "Volvo", "BMW"];
  1. 使用 JavaScript 关键词 new 创建数组。(不推荐)
JavaScript 复制代码
var cars = new Array("Saab", "Volvo", "BMW");

push 向数组末尾添加一个或多个元素,并返回新的长度

js 复制代码
const arr = [1, 2, 3];
arr.push(4);
// 现在 arr 为 [1, 2, 3, 4]

unshift 向数组的开头添加一个或多个元素,并返回新的长度

js 复制代码
const arr = [2, 3];
arr.unshift(1);
// 现在 arr 为 [1, 2, 3]

pop 移除并返回数组的最后一个元素

js 复制代码
const arr = [1, 2, 3];
const poppedElement = arr.pop(); // poppedElement = 3
// 现在 arr 为 [1, 2]

shift 移除并返回数组的第一个元素

js 复制代码
const arr = [1, 2, 3];
const shiftedElement = arr.shift(); // shiftedElement = 1
// 现在 arr 为 [2, 3]

splice 从数组中添加/删除元素,获得一个新数组

js 复制代码
const arr = [1, 2, 3, 4, 5];
arr.splice(2, 1); // 从索引2开始删除1个元素
// 现在 arr 为 [1, 2, 4, 5]

var nums = [1,2,3,7,8,9];
var newElements = [4,5,6];
nums.splice(3,0,newElements);
print(nums); // 1,2,3,4,5,6,7,8,9

slice 返回数组的一部分,不修改原数组

js 复制代码
const arr = [1, 2, 3, 4, 5];
const slicedArr = arr.slice(2, 4); // 从索引2到索引4(不包括)的元素
// slicedArr 为 [3, 4], arr 仍为 [1, 2, 3, 4, 5]

concat 将两个或多个数组合并成一个新数组

js 复制代码
const arr1 = [1, 2];
const arr2 = [3, 4];
const mergedArr = arr1.concat(arr2);
// mergedArr 为 [1, 2, 3, 4]

every 检测数组中的所有元素是否都符合指定条件

js 复制代码
const arr = [1, 2, 3, 4, 5];

// 检查数组中的所有元素是否都大于0
const allGreaterThanZero = arr.every(element => element > 0);
// allGreaterThanZero 为 true,因为所有元素都大于0

// 检查数组中的所有元素是否都是偶数
const allEvenNumbers = arr.every(element => element % 2 === 0);
// allEvenNumbers 为 false,因为数组中有一个奇数(1)

some 测试数组的至少一个元素是否通过了指定函数的测试

js 复制代码
const arr = [1, 2, 3];
const hasEven = arr.some(item => item % 2 === 0);
// hasEven 为 true

forEach 遍历数组的每个元素并执行提供的函数

js 复制代码
const arr = [1, 2, 3];
arr.forEach(item => {
    console.log(item);
});
// 输出: 1
// 输出: 2
// 输出: 3

map 遍历数组的每个元素并返回一个新数组,新数组的元素由回调函数的返回值组成

js 复制代码
const arr = [1, 2, 3];
const doubledArr = arr.map(item => item * 2);
// doubledArr 为 [2, 4, 6]

filter 筛选出数组中满足条件的元素,并将这些元素放入一个新数组中返回

js 复制代码
const arr = [1, 2, 3, 4, 5];

// 筛选出数组中的所有偶数
const evenNumbers = arr.filter(element => element % 2 === 0);
// evenNumbers 为 [2, 4]

// 筛选出数组中大于2的元素
const greaterThanTwo = arr.filter(element => element > 2);
// greaterThanTwo 为 [3, 4, 5]

reduce 将数组中的元素通过指定的函数进行累积计算,最终返回一个值

js 复制代码
const arr = [1, 2, 3, 4, 5];

// 计算数组中所有元素的和
const sum = arr.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
// sum 为 15 (1 + 2 + 3 + 4 + 5)

// 找出数组中的最大值
const max = arr.reduce((accumulator, currentValue) => Math.max(accumulator, currentValue), arr[0]);
// max 为 5

reduceRight() 类似于 reduce() 方法,但是从数组的末尾开始执行

js 复制代码
const arr = ['a', 'b', 'c'];
const reversedStr = arr.reduceRight((accumulator, currentValue) => accumulator + currentValue);
// reversedStr 为 'cba'

for...of 很方便地迭代数组中的元素,而无需手动管理索引

js 复制代码
const arr = [1, 2, 3, 4, 5];

for (const element of arr) {
  console.log(element);
}
// 输出: 1 2 3 4 5

@@iterator 返回一个包含数组键值对的迭代器对象,可以通过同步调用得到数组元素的键值对

js 复制代码
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];

let iterator = numbers[Symbol.iterator]()
iterator.next().value // 1
iterator.next().value // 2
iterator.next().value // 3
iterator.next().value // 4
iterator.next().value // 5

entries 返回数组的键值对的迭代器

js 复制代码
const arr = ['a', 'b', 'c'];
const entry = arr.entries();

for (const [index, value] of entry) {
    console.log(index, value); // 0 'a', 1 'b', 2 'c'
}

keys 返回数组的索引/键的迭代器

js 复制代码
const arr = ['a', 'b', 'c'];
const keys = arr.keys();

for (const key of keys) {
    console.log(key); // 0, 1, 2
}

values 返回数组的值的迭代器

js 复制代码
const arr = ['a', 'b', 'c'];
const values = arr.values();

for (const value of values) {
    console.log(value); // 'a', 'b', 'c'
}

from 通过类数组对象或可迭代对象创建一个新的数组实例

js 复制代码
const arr = Array.from('hello');
// arr 为 ['h', 'e', 'l', 'l', 'o']

of 一个静态方法,用于创建一个新的数组实例,该数组包含任意数量的参数

js 复制代码
const arr = Array.of(1, 2, 3, 4, 5);
// arr 为 [1, 2, 3, 4, 5]

const emptyArray = Array.of();
// emptyArray 为 []

fill 用一个固定值填充数组的所有元素

js 复制代码
const arr = [1, 2, 3, 4, 5];
arr.fill(0, 2, 4); // 从索引2开始到索引4之前的位置填充0
// arr 变为 [1, 2, 0, 0, 5]

copyWithin 复制数组的一部分到同一数组中的另一个位置,并返回修改后的数组

js 复制代码
// array.copyWithin(target, start, end)
// 目标位置索引 `target`:指的是要复制到的位置。
// 复制的起始位置索引 `start`:指的是要复制的起始位置。
// 复制的结束位置索引 `end`:指的是要复制的结束位置。

var array = [1, 2, 3, 4, 5];
// 将从索引 0 开始的元素复制到索引 3 处,覆盖后面的元素
array.copyWithin(3, 0);
console.log(array); // 输出: [1, 2, 3, 1, 2]
// 目标位置索引是 `3`,表示我们要将复制的元素粘贴到数组中索引为 `3` 的位置。
// 起始位置索引是 `0`,表示我们从数组的开头开始复制元素。
// 没有提供 `end` 参数,因此默认为数组末尾。


const arr = [1, 2, 3, 4, 5];
arr.copyWithin(0, 3, 4); // 从索引3开始复制到索引4之前的位置
// arr 变为 [4, 2, 3, 4, 5]

reverse 反转数组中元素的顺序,修改原数组

js 复制代码
const arr = [1, 2, 3, 4, 5];
arr.reverse();
// arr 变为 [5, 4, 3, 2, 1]

sort 对数组元素进行排序,默认按照字符串 Unicode 顺序排序,修改原数组

js 复制代码
const arr = [3, 1, 4, 1, 5, 9, 2, 6];
arr.sort((a, b) => a - b); // 数字升序排序
// arr 变为 [1, 1, 2, 3, 4, 5, 6, 9]

var nums = [3,1,2,100,4,200];
nums.sort();
print(nums); // 1,100,2,200,3,4

function compare(num1, num2) {
    return num1 - num2;
}
var nums = [3,1,2,100,4,200];
nums.sort(compare);
print(nums); // 1,2,3,4,100,200

indexOf 在数组中查找指定元素并返回其第一次出现的索引,如果数组中不存在该元素,则返回 -1

js 复制代码
const arr = [1, 2, 3, 4, 5];

const index = arr.indexOf(3);
// index 为 2

const notFoundIndex = arr.indexOf(6);
// notFoundIndex 为 -1,因为数组中不存在元素 6

const fromIndex = arr.indexOf(2, 2);
// fromIndex 为 -1,因为从索引 2 开始后面没有元素等于 2

lastIndexOf 从数组的末尾开始搜索指定的元素,并返回它在数组中最后一次出现的索引。如果数组中不存在该元素,则返回 -1

js 复制代码
const arr = [1, 2, 3, 4, 3, 2, 1];

const lastIndex = arr.lastIndexOf(3);
// lastIndex 为 4,因为元素 3 在索引 4 处最后一次出现

const notFoundIndex = arr.lastIndexOf(5);
// notFoundIndex 为 -1,因为数组中不存在元素 5

const fromIndex = arr.lastIndexOf(2, 3);
// fromIndex 为 1,因为从索引 3 开始向前搜索,找到元素 2 的最后一次出现在索引 1 处

find 查找数组中第一个满足条件的元素,并返回该元素。如果找到满足条件的元素,则返回该元素;如果找不到,则返回 undefined

js 复制代码
const arr = [1, 2, 3, 4, 5];

const found = arr.find(element => element > 2);
// found 为 3,因为 3 是数组中第一个大于 2 的元素

const notFound = arr.find(element => element > 5);
// notFound 为 undefined,因为数组中没有大于 5 的元素

findIndex 返回数组中满足提供的测试函数的第一个元素的索引,否则返回 -1

js 复制代码
const arr = [1, 2, 3, 4, 5];
const foundIndex = arr.findIndex(item => item > 3);
// foundIndex 为 3

includes 判断数组是否包含指定的元素,返回布尔值

js 复制代码
const arr = [1, 2, 3, 4, 5];
const hasThree = arr.includes(3);
// hasThree 为 true

toString 将数组转换为字符串,返回一个字符串表示数组

js 复制代码
const arr = [1, 2, 3];
const str = arr.toString();
// str 为 "1,2,3"

join 将数组中所有元素连接成一个字符串

js 复制代码
const arr = [1, 2, 3];
const str = arr.join('-');
// str 为 "1-2-3"

valueOf 和 toString 类似,将数组作为字符串返回

js 复制代码
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May'];
document.getElementById("result").innerHTML = months.valueOf();

flat() 将嵌套数组扁平化为指定深度的新数组

js 复制代码
const arr = [1, [2, [3, 4]]];
const flatArr = arr.flat();
// flatArr 为 [1, 2, [3, 4]]

flatMap() 首先使用映射函数映射每个元素,然后将结果扁平化为一个新数组

js 复制代码
const arr = [1, 2, 3];
const doubledArr = arr.flatMap(item => [item, item * 2]);
// doubledArr 为 [1, 2, 2, 4, 3, 6]

isArray() 判断给定参数是否为数组

js 复制代码
const arr = [1, 2, 3];
const isArray = Array.isArray(arr); // true

列表

列表介绍:

  1. 列表是一组有序的数据、一种线性数据结构
  2. 每个列表中的数据项称为元素
  3. 元素的数量受内存控制(即:元素不是很多)
  4. 不包含任何元素的列表称为空列表
js 复制代码
// 创建 List 构造函数
function List() {
  this.listSize = 0 // 列表元素个数
  this.pos = 0 // 列表当前位置
  this.dataStore = [] // 初始化一个空数组用来保存列表元素
  this.clear = clear // 清空列表中的所有元素
  this.find = find // 查找元素
  this.toString = toString // 返回列表字符串形式
  this.insert = insert // 在现有元素后插入新元素
  this.append = append // 在列表元素末尾增加新元素
  this.remove = remove // 从列表中删除元素
  this.front = front // 从列表的当前位置移动到第一元素
  this.end = end // 从列表的当前位置移动到最后一个位置
  this.prev = prev // 将当前位置前移一个位置
  this.next = next // 将当前位置后移一个位置
  this.length = length // 列表包含元素的个数
  this.currPos = currPos // 返回列表当前位置方法
  this.moveTo = moveTo // 将当前位置移动到指定位置
  this.getElement = getElement // 显示当前的元素
  this.contains = contains // 是否包含该元素
}

function append(element) {
  this.dataStore[this.listSize++] = element
}

function find(element) {
  // 此处的++应置于之前 以便返回正确的索引
  for (let i = 0; i < this.dataStore.length; ++i) { // ++i 和 i++ 区别
    if (this.dataStore[i] == element) return i
  }
  return -1
}

function remove(element) {
  const foundAt = this.find(element)
  if (foundAt > -1) {
    this.dataStore.splice(foundAt, 1) // splice 和 slice 区别,各自使用方法
    --this.listSize
    console.log(this.dataStore, this.listSize)
    return
  }
  return false
}

function length() {
  // 列表自己维护的一个变量
  return this.listSize
}

function toString() {
  return this.dataStore
}

function insert(element, afterElemnt) {
  const insertPos = this.find(afterElemnt)
  if (insertPos > -1) {
    this.dataStore.splice(insertPos + 1, 0, element)
    ++this.listSize
    return true
  }
  return false
}

function clear() {
  delete this.dataStore
  this.dataStore = [] // 创建一个空数组 this.dataStore.length = 0 会你报错 this.dataStore是 undefined 的length 不存在
  this.listSize = this.pos = 0
}

function contains(element) {
  for (let i = 0; i < this.dataStore.length; ++i) {
    if (this.dataStore[i] == element) {
      return true
    }
  }
  return false
}

// 遍历列表
function front() {
  this.pos = 0
}

function end() {
  this.pos = this.listSize - 1
}

function prev() {
  if (this.pos > 0) --this.pos
}

function next() {
  if (this.pos < this.listSize) ++this.pos
}

function currPos() {
  return this.pos
}

function moveTo(position) {
  this.pos = position
}

function getElement() {
  return this.dataStore[this.pos]
}

适用场景

数组适用场景

  1. 需要快速访问元素:如果需要通过索引快速访问元素,数组是一个很好的选择。
  2. 固定大小的集合:当需要存储固定数量的元素时,例如存储一组数据的情况,可以使用数组。
  3. 数值计算:数组通常用于存储数值,因为它们支持快速的数值计算和访问。

列表适用场景

  1. 动态数据集合:当需要在运行时动态添加或删除元素时,列表是一个很好的选择。
  2. 数据结构的构建:许多常见的数据结构,如链表、栈和队列,都可以使用列表来实现。
  3. 对元素顺序敏感:如果需要保持元素的插入顺序,并且不关心访问元素的效率,可以使用列表。
  4. 不确定集合大小:当集合的大小不确定或需要频繁的大小变化时,列表比数组更灵活。

最后

脸皮厚的作者🫣想申请一个免费的 star 🌟,请各位领导批准!

请跳转 GitHub 地址,也大家请批评指导!

相关推荐
秦jh_6 分钟前
【Linux】多线程(概念,控制)
linux·运维·前端
蜗牛快跑21318 分钟前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程
Dread_lxy20 分钟前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
ChoSeitaku23 分钟前
链表循环及差集相关算法题|判断循环双链表是否对称|两循环单链表合并成循环链表|使双向循环链表有序|单循环链表改双向循环链表|两链表的差集(C)
c语言·算法·链表
Fuxiao___32 分钟前
不使用递归的决策树生成算法
算法
我爱工作&工作love我37 分钟前
1435:【例题3】曲线 一本通 代替三分
c++·算法
涔溪1 小时前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
白-胖-子1 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级
workflower1 小时前
数据结构练习题和答案
数据结构·算法·链表·线性回归