数据结构与算法(刺猬书)读书笔记(1)----数组
在JavaScript中,数组其实是一种特殊的对象,用来表示偏移量的索引是该对象的属性,所以JavaScript的数组本质上是对象。同时这些数字索引在内部会被转换成为字符串类型,因为JavaScript对象中的属性名必须是字符串。此外,JavaScript数组还有一个特点,就是数组的每一项可以保存任何类型的数据,而且,数组的大小是可以动态调整的。
1. 创建数组
数组的创建方法有两种,第一种是简单的声明一个数组变量:
var numbers = []; var numbers = [1, 2, 3, 4, 5]
由于数组就是一种特殊的对象,所以第三种是调用Array的构造函数创建数组。
var numbers = new Array(); var numbers = new Array(1, 2, 3, 4, 5);
这两种方法对比起来,使用[]操作符来声明数组变量被认为效率更高,所以推荐使用这种方法。
2. 对数组的整体性操作
数组的复制分为潜伏之和深复制两种。由于数组是特殊的对象,所以将数组赋值给一个变量的时候,赋值过去的只是这个数组的引用。如果通过原因用修改了数组的值,所有引用了这个数组的变量都相当于被修改成了新的值。所以在复制数组的时候,更好的方法是深复制,创建一个新数组,将现有数组中的每一个元素都复制到新数组去,这样就实现了完全的复制。
浅复制:
var nums = []; for (var i = 0; i < 100; ++i) { nums[i] = i + 1; } var samenums = nums; nums[0] = 400; print(samenums[0]); // 400
深复制:
function copy(arr1, arr2) { for (var i = 0; i < arr1.length; ++i) { arr2[i] = arr1[i]; } } var nums = []; for (var i = 0; i < 100; ++i) { nums[i] = i + 1; } var samenums = []; copy(nums, samenums); nums[0] = 400; print(samenums[0]); // 1
3. 数组相关的方法
3.1 由字符串生成数组
调用字符串对象的split()方法可以生成数组,在方法中传递分隔符,然后字符串将根据分隔符进行分割形成数组。
3.2 查找数组
indexOf():返回第一个与参数相同的元素的索引。
lastIndexOf():返回相同元素中最后一个元素的索引。
如果没找到相同元素则返回-1。
这里有一个查找方法基本的写法,就是如果没找到的话一般都会返回-1,而不是其他乱七八糟的东西。
3.3 数组的字符串表示
有两个方法可将数组转化为字符串:join() 和 toString()。除此之外,直接对一个数组使用print()函数时,系统会自动调用那个数组的toString()方法。
3.4 合并多个数组
concat()函数可以合并多个数组创建一个新数组。该方法的发起者是一个数组,参数是另一个数组。参数中所有元素都被连接到调用concat()方法的数组后面。
3.5 在数组中添加删除元素
添加元素:push() 和 unshift()
删除元素:pop() 和 shift()
万能方法:splice()
注意:这些方法都是直接对原数组进行操作的。
push()可将一个元素添加到数组末尾,unshift()可将元素添加在数组的开头。pop()可删除数组末尾的元素,shift()可删除数组第一个元素。
splice方法中可以提供三个参数:1. 起始索引
2. 需要删除的元素个数
3. 想要添加进数组的元素
通过合理的运用这三个参数即可实现添加或者删除元素。同时,splice()函数会返回删除掉的元素组成的数组,所以也可被用来从现有数组里截取一个新数组。但需要注意的是,该方法会修改原数组,所以用作截取数组时应该考虑是否希望原数组改变。
下面提供splice()三种用法的示例
添加元素:
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]
注意:这里传进去的希望添加进数组的元素如果是个数组,整个数组将会被看做一个元素被添加进数组,而不是将数组中的元素添加进数组。
如想要插入多个元素可以这样写:
var nums = [1, 2, 3, 7, 8, 9]; nums.splice(3, 0, 4, 5, 6); print(nums); // [1, 2, 3, 4, 5, 6, 7, 8, 9];
删除元素:
var nums = [1, 2, 3, 100, 200, 300, 400, 4, 5]; nums.splice(3, 4); print(nums); // 1,2,3,4,5
截取数组:
var num = [1, 2, 3, 4, 5, 6, 7, 8]; var someNum = num.splice(3, 3); var remainNum = num; print(someNum); // 4,5,6 print(remainNum); // 1,2,3,7,8
3.6 为数组排序
有两个排序相关算法:reverse() 和 sort()。reverse()可将数组中元素的顺序进行翻转。sort()允许传入比较函数,并对数组进行排序。
当sort()函数中没有传入任何参数时,无论是字符串还是数字,都是按照字典顺序对元素进行排序的:
var names = ["David", "Mike", "Cynthia", "Clayton", "Bryan", "Raymond"]; names.sort(); print(names); // Bryan,Clayton,Cynthia,David,Mike,Raymond 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
传入的函数应该返回一个正值或负值,如果是正值则第一个参数位于第二个参数前边,反之则第二个参数在前面。
3.7 迭代器方法
3.7.1 不生成新数组的迭代器方法
foreach():接受一个函数作为参数,对数组中的每个元素使用该函数。
every():接受一个返回值为布尔类型的函数,对数组中的每个元素使用该函数。如果所有的元素都使得该函数返回true,该函数返回true。
some():接受一个返回值为布尔类型的函数,只要有一个元素使得该函数返回true,该方法就返回true。
reduce():接受一个函数,返回一个值。该方法会从一个累加值开始,不断对累加值和数组中的后续元素调用该函数,直到数组中的最后一个元素,最后返回得到的累加值。reduce()接受的函数接受两个参数,第一个参数是到目前为止累加出来的值,第二个参数时现在的值。
reduceRight():从右到左执行。
3.7.2 生成新数组的迭代器方法
map():接受一个函数作为参数,返回一个新的数组,该数组的元素是对原有元素应用那个函数得到的结果。
filter():接受一个函数作为参数,返回所有能使该函数返回true的元素。
4. 二维和多维数组
JavaScript中没有二维数组,但可以通过在数组中插入数组元素来实现二维数组。
var twod = []; var rows = 5; for (var i = 0; i < rows; ++i) { twod[i] = []; }
关于如何创建二维数组,书中提到了一个最佳实践,是JavaScript: The Good Parts (O'Reilly)一书中64页的例子。
Array.matrix = function(numrows, numcols, initial) { var arr = []; for (var i = 0; i < numrows; ++i) { // 设置行 var columns = []; for (var j = 0; j < numcols; ++j) { // 设置列 columns[j] = initial; } arr[i] = columns; } return arr; }
这样就形成了一个numrows行,numcols列的二维数组,可以通过arr[i][j]访问到其中的每一个元素。
如果要对二维数组中的元素进行处理,也可通过这种嵌套循环的方式来访问到每个元素并对每个元素进行操作,此处要注意循环参数最好参照arr.length进行循环,这样即使是参差不齐的数组也可以很好的进行处理。
5. 对象与数组
数组中也可包含对象,对象中也可包含数组,这使得数组的应用更加广阔。