数据结构与算法(刺猬书)读书笔记(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. 对象与数组

数组中也可包含对象,对象中也可包含数组,这使得数组的应用更加广阔。

时间: 2024-10-21 00:23:49

数据结构与算法(刺猬书)读书笔记(1)----数组的相关文章

《ACM/ICPC 算法训练教程》读书笔记 之 数据结构(线段树详解)

依然延续第一篇读书笔记,这一篇是基于<ACM/ICPC 算法训练教程>上关于线段树的讲解的总结和修改(这本书在线段树这里Error非常多),但是总体来说这本书关于具体算法的讲解和案例都是不错的. 线段树简介 这是一种二叉搜索树,类似于区间树,是一种描述线段的树形数据结构,也是ACMer必学的一种数据结构,主要用于查询对一段数据的处理和存储查询,对时间度的优化也是较为明显的,优化后的时间复杂为O(logN).此外,线段树还可以拓展为点树,ZWK线段树等等,与此类似的还有树状数组等等. 例如:要将

《算法导论》读书笔记(五)

摘要: 本章介绍了二叉查找树的概念及操作.主要内容包括二叉查找树的性质,如何在二叉查找树中查找最大值.最小值和给定的值,如何找出某一个元素的前驱和后继,如何在二叉查找树中进行插入和删除操作.在二叉查找树上执行这些基本操作的时间与树的高度成正比,一棵随机构造的二叉查找树的期望高度为O(lgn),从而基本动态集合的操作平均时间为θ(lgn). 1.二叉查找树 二叉查找树是按照二叉树结构来组织的,因此可以用二叉链表结构表示.二叉查找树中的关键字的存储方式满足的特征是:设x为二叉查找树中的一个结点.如果

《算法导论》读书笔记(七)

前言:贪心算法也是用来解决最优化问题,将一个问题分成子问题,在现在子问题最优解的时,选择当前看起来是最优的解,期望通过所做的局部最优选择来产生一个全局最优解.书中先从活动选择问题来引入贪心算法,分别采用动态规划方法和贪心算法进行分析.本篇笔记给出活动选择问题的详细分析过程,并给出详细的实现代码进行测试验证.关于贪心算法的详细分析过程,下次在讨论. 1.活动选择问题描述   有一个需要使用每个资源的n个活动组成的集合S= {a1,a2,···,an },资源每次只能由一个活动使用.每个活动ai都有

《算法导论》读书笔记(三)

本章介绍了快速排序及其算法分析,快速排序采用的是分治算法思想,对包含n个数的输入数组,最坏情况下运行时间为θ(n^2),但是平均性能相当好,期望的运行时间为θ(nlgn).另外快速排序能够就地排序(我理解是不需要引入额外的辅助空间,每次划分能确定一个元素的具体位置),在虚拟环境中能很好的工作. 1.快速排序的描述 快速排序算法采用的分治算法,因此对一个子数组A[p-r]进行快速排序的三个步骤为: (1)分解:数组A[p...r]被划分为两个(可能为空)子数组A[p...q-1]和A[q+1...

《算法导论》读书笔记(一)

本章是本书的开篇,介绍了什么是算法,为什么要学习算法,算法在计算机中的地位及作用. 算法(algorithm)简单来说就是定义良好的计算机过程,它取一个或一组值作为输入,并产生出一个或一组值作为输出.即算法就是一系列的计算步骤,用来将输入数据转换成输出数据. 书中有一句话非常好: Having a solid base of algorithm knowledge and technique is one characteristic that separates the truly skill

《ACM/ICPC 算法训练教程》读书笔记一之数据结构(堆)

书籍简评:<ACM/ICPC 算法训练教程>这本书是余立功主编的,代码来自南京理工大学ACM集训队代码库,所以小编看过之后发现确实很实用,适合集训的时候刷题啊~~,当时是听了集训队final的意见买的,感觉还是不错滴. 相对于其他ACM书籍来说,当然如书名所言,这是一本算法训练书,有着大量的算法实战题目和代码,尽管小编还是发现了些许错误= =,有部分注释的语序习惯也有点不太合我的胃口.实战题目较多是比较水的题,但也正因此才能帮助不少新手入门,个人认为还是一本不错的算法书,当然自学还是需要下不少

《算法导论》读书笔记--为什么要读

以前一直想读一遍<算法导论>,不过由于自己犯懒一直没有开始.前两天报一个实习的测试,小算法都不会写,感觉比较糟糕,意识到应该开始读算法了. 作为数学系的人,虽然没有学过数据结构和算法,不过想来好好读不会很难:加上自己对于语言的基础太差,有不忍直视的"码力",学算法正好又能顺便用一遍c++,一举两得. 那么为什么要写博客呢?首要的当然是自我监督,其次,写的博客可以作为非常珍贵的资料,用于以后的复习. 下面说说打算怎么读:1.把每一部分都读懂 2.把关键点提取出来写成笔记 3.

数据结构与算法C++描述学习笔记1、辗转相除——欧几里得算法

前面学了一个星期的C++,以前阅读C++代码有些困难,现在好一些了.做了一些NOI的题目,这也是一个长期的目标中的一环.做到动态规划的相关题目时发现很多问题思考不通透,所以开始系统学习.学习的第一本是<数据结构与算法C++描述>第三版,边学边做一些笔记.所以这些笔记中的代码有很多将会非常简单,甚至可能只有一个记录或者结论. 辗转相除法用来求两个整数的最大公约数,即能同时整除两个数的最大整数.程序如下: int gdc(int m,int n){ int rem; while(n!=0){ //

&lt;&lt;数据结构与算法Javascript描述&gt;&gt;随笔笔记

序言: 程序问题三步走-->① 将问题抽象为数据结构 -->② 并根据相关算法来操作数据结构 -->③ 调用API来显示结果 一.数组和列表 二.栈和队列 三.链表 四.字典 五.散列 六.集合 七.二叉树 八.图 九.热门算法 

《算法导论》读书笔记之第16章 0-1背包问题—动态规划求解

原文:http://www.cnblogs.com/Anker/archive/2013/05/04/3059070.html 1.前言 前段时间忙着搞毕业论文,看书效率不高,导致博客一个多月没有更新了.前段时间真是有些堕落啊,混日子的感觉,很少不爽.今天开始继续看算法导论.今天继续学习动态规划和贪心算法.首先简单的介绍一下动态规划与贪心算法的各自特点及其区别.然后针对0-1背包问题进行讨论.最后给出一个简单的测试例子,联系动态规划实现0-1背包问题. 2.动态规划与贪心算法 关于动态规划的总结