《学习JavaScript数据结构与算法》第三章 14000字笔记

Posted 白瑕

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《学习JavaScript数据结构与算法》第三章 14000字笔记相关的知识,希望对你有一定的参考价值。


前言

本文包括数组操作方法、ES6新增数组功能、JS矩阵、类型化数组等;

前面是基础部分,如果你不是小白的话…个人认为可以从第三章开始?
上一篇:《学习JavaScript数据结构与算法》第二章 ES和TS概述


一、创建 && 初始化数组

使用javascript声明, 创建和初始化数组;

使用new关键字,来简单的声明并初始化一个数组。
该种方式的优点是可以直接在声明时就确定好数组的长度:

daysOfweek = new Array(数组长度,数字型);
daysOfweek1 = new Array(7);

或者直接使用中括号形式:

let daysOfweek = [];
let daysOfweek1 = ['one', 'two', 'three'];

get数组长度:

console.log(数组名.length);

二、操作数组

添加元素于末尾

直接将要添加的数组元素赋值给数组的最后一位,但这种方法一次性只能添加一个元素:

let array = ["one", "two", "three"];
array[array.length] = 新数组元素;
console.log(array);

我们在实战中更多使用的方法是push(),这是一个专用于处理数组的方法:

let array = ["one", "two", "three"];
array.push(要添加的元素1, 要添加的元素2, ...);
array.push(array2[3]);

可以一次性将多个元素依次加入数组的末尾.


添加元素于开头

将新的数组元素直接添加至数组开头, 实操一般会使用unshift方法:

let numbers = [3, 4, 55];
numbers.unshift(-2);
unmbers.unshift(-2, 3);
console.log(numbers);

从数组末尾开始删除元素

使用pop()方法来从末尾删除数组中的元素:
书上并没有详细阐述这一方法, 只给了一个实例, 只好跑一下试试,

let numbers = [1, 2, 3, 4, 5];
numbers.pop();
console.log(numbers);


pop()方法固定只移除最后一个元素, 给参数也没用…


从数组开头开始删除元素

for(let i = 0; i < numbers.length; i++) {
  numbers[i] = numbers[i + 1];
}

这相当于在数组序列号不变的情况下将所有数组元素整体左移了一个单位,
但在这种情况下输出数组会发现数组的长度依旧未被改变,这说明数组中必然有一个元素的值为undefined:

可以看到, 我们只是把数组第一位的值用第二位进行了覆盖, 第一位并未被删除.

但在实战中我们一般使用shift方法:

let num = [1, 2, 3];
numbers.shift();

这种方法会直接导致数组长度减小.


在数组任意位置添加或删除元素

删除和添加操作均可使用splice()来完成;
使用splice()方法, 通过指定起始位置和删除个数来完成删除操作;

//注意是从左往右删;
numbers.splice(起始序列号, 删除数量);

使用splice()方法, 通过指定起始位置和传入要添加的元素来完成添加:

//执行添加操作, 第二个参数请传0;
number.splice(起始序列号, 删除数量, 元素1, 元素2, 元素3, ...)

你看可以看到第二个参数依旧是有效的?
我只打算添加元素, 你要删除也可以, 我慷慨的允许你删0个 .


三、二维 多维数组

矩阵, 指包含二维数组在内的数组含有数组的结构;

JavaScript只支持一维数组并不支持矩阵,但是可以用如下数组嵌套的方法来实现矩阵.

构建二维数组

一维数组看作流水线, 把数组元素看作流水线上的一个个商品 ,那么二维数组就是流水线上一组组堆出了高度
的商品:

就像这样:

     ︹  ︹     ︹
     6   4      3
     3   5      9
     2   1      0
[ 3,,, 5,, 6 ]

进行了一个维度的跨升, 但肯定是不能直接在代码里写这么个流水线的, 還是得這麽寫:

[
3, 
[6, 3, 2],
[4, 5, 1],
5,
[3, 9, 0],
6,
]

迭代二维数组

用双层for来进行迭代, 同样的, 三维数组可以使用三层for迭代:

function printMatrix(myMatrix) {
  for(let i = 0; i < myMatrix.length; i++) {
    for(let j = 0; j < myMatrix[i].length; j++) {
      console.log(myMatrix[i][j]);
    }
  }
}

要取到某个元素,可直接使用如下方式:
array[2][1];


四、JavaScript数组方法参考

方法说明
concat连接两个或者更多数组
foreach对数组中每个元素执行函数,无返回值
every对数组中每个元素执行函数, 如果每个元素的执行都返回true,every()返回true;
filter对数组中每个元素执行函数, 返回由所有执行时返回true的元素组成的数组
map对数组中每个元素执行函数, 返回所有执行结果组成的数组
some对数组中每个元素执行函数, 只要有一个元素返回true,some()就返回true
join将所有数组元素链接为一个字符串
indexOf返回找到的第一个与给定参数相等的数组元素的索引号
lastIndexOf返回找到的所有与给定参数相等的数组元素中索引号最大的那个, 即返回所有与参数相等的元素中最靠右的那个
reverse颠倒数组元素的顺序,索引号不变
slice依据传入的索引值将将索引范围内的元素作为新数组返回
sort按照英文字母顺序对数组进行排序, 支持传入【指定排序方法的函数】作为参数
toString将数组转换为字符串返回
valueOf将数组转换为字符串返回, 与toSting相似

这其中的一些方法在函数式编程中十分有用;
这些我就不多记了, 都能查到.


數組反排序: reverse()

對數組使用reverse()方法可以獲得一個數組的反序形態, 這個沒什麽好説的,
但是書上在對數組使用了reverse()之後還進行了一次sort排序, 我先去查了一下sort的特性,如果调用 sort() 方法时没有传递参数, 则按字母顺序对数组中的元素进行排序(就是按abcde這種順序);
但是書上給的示例是數字數組啊 ,這?

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
numbers.reverse();
console.log(numbers);
numbers.sort()
console.log(numbers);


你可以看到用sort排序後又變成了亂七八糟的樣子, 因爲sort()進行排序時, 發現元素不是字符串, 它會试图把数组元素转换成字符串再进行比较.
那就不用它默認的排序方式了, 反正sort支持傳入compareFunction比較函數,:

//比較函數使用了箭頭函數: (a, b) => {}

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
numbers.reverse();
numbers.sort();
console.log(numbers.sort((a, b) => a - b));

/
//sort()會根據返回值的正負來判讀值之間的大小關係,相當於如下;

function compare() {
  if (a < b) {
    return -1;
  }
  if (a > b) {
    return 1;
  }
return 0;
}
numbers.sort(compare);  //向sort傳入比較函數作參;

這樣即實現了將反序數組重新撥正的目的;


值匹配搜索: indexOf && lastindexOf

先來看indexOf吧:
indexOf() 返回與參數匹配的第一個元素的索引.

console.log(numbers.indexOf(10)); //返回9, 因爲值10所在的索引為9;
console.log(numbers.indexOf(100)); //返回-1, 因爲數組裏壓根沒有100;

對於 indexOf() 就是能找到的就會輸出目標數組元素的索引號, 找不到不存在的就輸出-1;

再來看lastIndexOf():
lastIndexOf返回與參數匹配的最後一個元素的索引.
意思就是:如果針對一個數組進行的查找產生了多個滿足條件的結果,豈會需選取最靠右的結果的索引號作爲返回值;

numbers.push(10);
console.log(numbers.lastIndexOf(10));  //10
console.log(numbers.lastIndexOf(100));  //-1

輸出數組為字符串: toString && join

兩個方法都可以將數組轉換爲字符串, 但是…還是有點區別,那就是
toString是直接將數組元素硬性轉換為字符串, 説白了就是直接把外面的中括號去掉直接讓裏面的數組元素和逗號暴露出來;

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(numbers.toString());

然後就直接變成這樣了, 這樣一般都沒法直接用, 還得拆吧拆吧之類的處理一下…

然後就是join了, 這個方法特點就是你可以指定各個數組元素拆分後以什麽東西進行連接(原本在數組裏不是逗號嘛), 然後拆開之後你可以把它變成"1QAQ2QAQ3QAQ4"或者"1@2@3"之類的這種 (這其實有點像php裏的那個implode方法)…
示例:

const numberString = numbers.join("QAQ");
console.log(numbersString);


五、ES6数组的新功能

新增方法说明
@@iterator返回一个包含数组键值对的迭代器对象,可以通过数组同步调用来得到数组元素的键值对
copyWithin复制数组中一系列元素到同一数组指定的起始位置
entries返回包含数组所有键值对的@@iterator(即索引號與值的键值对)
keys返回包含数组所有索引号的@@iterator(即包含索引號的對象)
values返回包含数组中所有值的@@iterator(即包含值的對象)
includes速查, 数组中是否包含某个元素,返回布尔值(這是出自ECMAS7的方法)
find可以注册回调函数, 其会根据回调函数规定的条件从数组中查找元素, 如果找到该元素则会返回.
findIndex可以注册回调函数, 其会根据回调函数规定的条件从数组中查找元素, 找到后会返回其索引号
fill使用静态值填充数组
from根据已有数组创建一个新数组
of根据传入的参数创建一个新数组

使用for…of来进行遍历

for…of 對可迭代对象(包括 Array, Map, Set, String, TypedArray, arguments等)執行循环, 为每个不同属性的值执行语句

let numbers = [3, 4, 7, 6];
for (const n of numbers) {
  console.log(n);
}

公式:

let 數組名 = [元素1, 元素2, 元素3, 元素4];
for (const key名稱 of 數組名) {
  console.log(key名稱);
}


你可以看到在for…of語句中,key不再是for中的索引號, 而是各個數組元素;


@@iterator对象

ES6为Array类增加了一个@@iterator属性, 需要通过Symbol.iterator来访问.

let numbers = [1, 2, 3, 4, 5];
let iterator = numbers[Symbol.iterator]();
console.log(iterator.next().value);
console.log(iterator.next().value);
console.log(iterator.next().value);
console.log(iterator.next().value);
console.log(iterator.next().value);

形成對next()的反復调用,依次得到数组中的值:


取出索引號與值的键值对:entries()

在上面的表中我提到了这个entries(), 其返回包含数组所有键值对的@@iterator.

let aEntries = number.entries();
console.log(aEntries.next().value);
console.log(aEntries.next().value);
console.log(aEntries.next().value);

這樣寫自然是不好看的,那麽:
示例:

let array = [1, 2, 3];
aEntries = array.entries();
for(const n of aEntries) {
  console.log(n);
}

公式:

let 數組名 = [元素1, 元素2, 元素3];
自定義名 = 數組名.entries();
for(const key名稱 of 自定義名) {
  console.log(key名稱);
}


“使用集合、字典、散列表等數據結構時, 能夠取出鍵值對是十分有用的”


返回包含索引號的對象:keys()

keys返回包含數組索引號的@@iterator:
示例:

let array = [5, 4, 3, 2, 1];
const aKeys = array.keys();
for (let i = 0; i <= array.length;i++) {
  console.log(aKeys.next());
}

公式:

let 數組名 = [元素1, 元素2, 元素3, 元素4, 元素5];
const 自定義名 = 數組名.keys();
for (let i = 0; i <= 數組名.length;i++) {
  console.log(自定義名.next());
}


至於後面那個done,它在英文中有"已完成"的意思,放在這裏即"是否已完成",
如果它的值為false説明這個數組還沒被迭代完成, 你可以看到, 儅數組迭代到了末尾,done變爲true;
“一旦沒有可迭代的值, aKeys.next()就會返回一個value屬性為undedined, done屬性為true的對象”;


返回包含元素值的對象:values()

values()與keys()則是截然相反, 它不返回索引號而是返回元素的值:

示例:

        let array = [5, 4, 3, 2, 1];
        const aKeys = array.values();
        for (let i = 0; i <= array.length; i++) {
            console.log(aKeys.next());
        }


done的作用同keys(), 用以判定當前數組是否迭代完成;


查找滿足函數條件的值: find() && findIndex()

這倆方法都能接收回調函數, 作用是去搜索能滿足回調函數條件的值,并且返回這些值.
但是也有些區別, 我們先來看find()吧:
find()返回找到的第一個滿足函數條件的值,重點在值.
而findIndex()返回的是滿足條件的值的索引號(見示例末行);
示例:

//我這裏把回調函數寫外面了,像addEventListener那樣寫裏面也可以的.
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];

function multipleOf13(element) {
  return (element % 13 == 0);
}

console.log(numbers.find(multipleOf13)); //13
//因爲數組裏滿足13倍數的就只有13一個, 所以直接返回了元素值13.


console.log(numbers.findIndex(multipleOf13)); //12
//數組裏滿足13倍數的只有13一個, 所以直接返回值13的索引號12.

根據已有數組創建新的數組: from()

from()方法根據已有的數組創建一個新的數組, 比如要複製numbers數組如下:

let numbers = [5, 4, 3, 2, 1];
let numbers2 = Array.from(numbers);  
//from()利用numbers數組生成新數組numbers2
console.log(numbers2);


但這樣直接全盤搬過來似乎意義不大, 大多數時候我們需要進行篩選來創建新的數組, 這下第二個參數位就能派上用場了, 它支持傳入一個用於過濾值的函數:

let evens = Array.from(numbers, i => (i % 2 == 0));
//from()利用numbers數組生成新數組evens;
//並根據數組元素的奇偶來決定填充的布爾值;
console.log(evens);


依據傳入的參數創建新數組: Array.of()

Array.of 方法根據傳入的參數創建一個新的數組:

let numbers3 = Array.of(1);
let numbers4 = Array.of(1, 2, 3, 4, 5);
//相當於let numbers4 = [1, 2, 3, 4, 5];
console.log(numbers3);
console.log(numbers4);

你也可以向其内部傳入數組作爲參數! 還記得前面説到的展開運算符嗎?

let numbers4 = [1, 2, 3, 4];
let numbersCopy = Array.of(...numbers4);
//相當於let numbersCopy = Array.of(1, 2, 3, 4);
console.log(numbersCopy);


使用靜態值來填充數組: fill()

fill()可以讓你的數組充滿某個值, 你也可以用索引號界定範圍, 讓某個範圍的元素全部爲某個值;

數組名.fill(要填充的值, 開始処索引號(可選), 結束処索引號(可選));

不過要記著開始索引號對應的值會遭到填充, 但是結束処對應的值不會遭到填充, 比如開始処3, 結束処5, 那被填充的索引只有3,4.

let numbersCopy = Array.of(1, 2, 3, 4, 5, 6);
numbersCopy.fill(0, 2, 4);
console.log(numbersCopy);


變數組某一段與另一段相同: copyWithin()

copyWithin()方法複製(注意是複製,不會對受複製者有影響)數組中一系列元素到指定的位置進行替換.
原理: 將參數二及其右邊的數組元素複製, 用於替換參數一及其右邊的相應個數的數組元素, 一定不會改變數組長度;

下面我先只改變參數一即插入點:

let copyArray JavaScript算法(冒泡排序选择排序与插入排序)

JavaScript数据结构与算法——第三章 栈

拿捏javascript数据结构与算法(上)

郑捷《机器学习算法原理与编程实践》学习笔记(第三章 决策树的发展)_Scikit-learn与回归树

萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第四节 PCA与梯度上升 (下)实操篇

JavaScript算法(归并排序与快速排序)