版权声明
版权是一件很重要的事情,能写一本书或者翻译一本书需要付出艰辛的劳动。刚刚我已经跟机械工业出版社的人联系,欣喜的是他们说可以发布学习笔记,我才贴出来。 虽然贴出来了,但是如果有任何不妥的地方,本人承诺立即删除文章。也希望各位读者能够尊重别人的劳动果实。
前言
为什么要读《数据结构和算法》,或者把这个问题推广下为什么要不断的读书呢?是工作做不下去了吗?其实不是的,工作已经稳稳的。是热爱吗?也不是的,其实我心里也很不想读。因为一个很直观的感受,读了这些东西感觉也没啥用,真的,这些知识点不会直接对工作产生任何影响,读了感觉也就是在浪费时间。而且读书确实是一件蛮痛苦的事情。那说了这么多,为什么还要读呢?其实是面试刺激的,找工作经历了一段时间的面试,让自己发现了自己原来是个渣渣,尤其是在算法方面。所以现在要重新读书,把那些自己薄弱的地方补起来,让自己变得更强大。也让自己的视野能够更开阔,看到更大的风景。
第1章 javascript编程环境和模型
1.1 JavaScript环境
- 浏览器环境
- node环境
- spiderMonkey(Mozilla开发的类似于node的环境)
1.2 JavaScript编程实践
- 声明和初始化变量——什么是局部变量、什么是全局变量
- Javascript中的算术运算和数学库函数——关于js中的加减乘除和Math函数
- 判断结构——if、else、switch的用法
- 循环结构——for、while的用法
- 函数——如何声明一个函数
- 变量作用域——js中变量的作用域是函数作用域而不是块作用域
- 递归——js中是用于递归的,如果递归深度超过了js的处理能力,就要寻找其他方法
- 对象和面向对象编程——js如何定义对象和继承对象的
个人点评:此处讲的知识点实在太浅显了,连入门都算不上,完全可以不用这段。如果大家想了解js的话,还是要去看ES6的相关教程。
第2章 数组
2.1 JavaScript中关于数组的定义
数组:一个存储元素的线性集合,元素可以通过索引来任意存取,索引通常是数字。
2.2 使用数组
2.2.1 创建数组
- 声明一个数组变量
- 通过Array构造函数
let arr = [];
let numberArr = new Array(1,2,3)
2.2.2 读写数组
通过[]操作符来读取数组中的元素
2.2.3 由字符串生成数组
通过split方法把字符串变成数组。
2.2.4 对数组的基本操作
let arr = [1,2,3]
let brr = arr
这一节讲的就是简单的这种赋值,顺便还特别浅显的说了下深复制和浅复制的区别。感兴趣的同学可以自行了解。面试必考!!!
2.3 存取函数
2.3.1 查找元素
这一节主要讲了几个方法的运用,比较浅显。es6中,新增了find、includes等方法可以自行了解
- indexOf
- lastIndexOf
2.3.2 数组的字符串表示
主要讲的是如何把数组转化成字符串
- join
- toString
2.3.3 由已有数组创建新数组
- concat
- splice
2.4可变函数
以下笔记不再写三级标题的序号了,整本书分的节太多了,略显啰嗦。为了省事,小标题序号省略。也对很啰嗦的章节进行归纳。
这一节主要也是讲数组的一些常见方法
- push
- pop
- shift
- unshift
- splice
- reverse
- sort
2.5 迭代器方法
这一节讲数组遍历的方法
- forEach
- every
- some
- reduce
- map
- filter
2.6 二维和多维数组
这一节讲如何创建和遍历二维数组。
2.7 对象数组
这一节讲的是数组中的元素可以是对象,以及如何获取数组中某个对象。
2.8 对象
这一节讲的是对象的某个属性可以是数组,以及如何访问对象的数组属性
个人点评:这一章讲的也都是地球人都知道的知识,而且讲的也都很浅显。不过这一章所涉及到的知识点倒都是重点,无论面试还是工作,都经常用到。
3 列表
3.1 列表的抽象数据类型定义
列表是一组有序的数据。每个列表的数据项被称为元素。在js中元素可以是任意数据类型。列表可以保存多少元素并没有事先限定,实际使用受程序内存限制。
列表的方法和属性
| 方法和属性 | 含义 |
|---|---|
| listSize(属性) | 列表的元素个数 |
| pos(属性) | 列表的当前位置 |
| length(属性) | 返回列表中元素的个数 |
| clear(方法) | 清空列表中的所有元素 |
| toString(方法) | 返回列表的字符串形式 |
| getElement(方法) | 返回当前位置的元素 |
| insert(方法) | 在现有的元素后插入新元素 |
| append(方法) | 在列表的末尾添加新元素 |
| remove(方法) | 从列表中删除元素 |
| front(方法) | 将当前列表的位置移动到第一个元素 |
| end(方法) | 将当前列表的位置移动到最后一个元素 |
| prev(方法) | 将当前位置前移一位 (原书中为后移一位) |
| next(方法) | 将当前位置后移一位 (原书中为前移一位) |
| hasNext(方法) | 判断是否有后一位 |
| hasPrev(方法) | 判断是否有前一位 |
| currPos(方法) | 返回列表的当前位置 |
| moveTo(方法) | 将当前位置移动到指定位置 |
3.2 实现列表类
原书是使用es5的写法,我改成class写法。具体怎么实现,其实很简单。代码如下,原书中有很多错误和不严谨的地方,我已经订正,注释的的为原书中的代码。
class List {
constructor() {
this.listSize = 0
this.pos = 0
this.dataStore = []
this.length = this.listSize
}
// 定义一个工具函数find,用于查找列表中是否包含某个元素。我们对NaN也做兼容处理,所以不能使用indexOf方法
find(element) {
let dataStore = this.dataStore
for (let i = 0; i < dataStore.length; i++) {
if (
element === dataStore[i] ||
(Number.isNaN(dataStore[i]) && Number.isNaN(element))
) {
return i
}
}
return -1
}
// append方法 给列表添加元素
append(element) {
this.dataStore[this.listSize++] = element
}
// remove 从列表中删除元素
remove(element) {
let index = this.find(element)
if (index > -1) {
this.dataStore.splice(index, 1)
--this.listSize
return true
}
return false
}
// length 属性,原书中实现这个属性的时候,写成了方法,我这里订正为属性
set length(value) {}
get length() {
return this.listSize
}
// 显示列表中的元素
toString() {
return this.dataStore
}
// 向现有的元素后面插入新元素
insert(element, after) {
let insertPos = this.find(after)
if (insertPos > -1) {
this.dataStore.splice(insertPos + 1, 0, element)
++this.listSize
return true
}
return false
}
// 清空列表中的所有元素,原书中的代码使用delete,而后又修改dataStore的length属性,我个人测试的时候报错,修改如下
/*
clear () {
delete this.dataStore
this.dataStore.length = 0
this.listSize = this.pos = 0
}
*/
clear() {
this.dataStore = []
this.listSize = this.pos = 0
}
// 判断给定的值是否在列表中,原书是遍历数组,然后==判断。这个很不妥,一个是存在类型转换,第二个是不能判断NaN,订正如下
/*
contains (element) {
for (var i = 0; i < this.dataStore.length; i++) {
if (this.dataStore[i] == element) {
return true
}
}
return false
}
*/
contains(element) {
return this.dataStore.includes(element)
}
// 将当前列表的位置移动到第一个元素
front() {
this.pos = 0
}
// 将当前列表的位置移动到最后一个元素
end() {
this.pos = this.listSize - 1
}
// 将当前位置前移一位,个人感觉原书这样子很不妥,pos为0的时候,竟然还可以继续往前移动,有点奇怪
prev() {
--this.pos
}
// 将当前位置后移一位,同样我个人感觉原书中提供的方法不太妥当,prev可以一直减少,为啥next不可以一直增加,所以对程序进行了一点修正
/*
next() {
if(this.pos<this.listSize){
++this.pos
}
}
*/
next() {
++this.pos
}
// 返回列表的当前位置
currPos() {
return this.pos
}
// 将当前位置移动到指定位置,个人感觉原书中的方法不妥,订正如下
/*
moveTo(position){
this.pos = position
}
*/
moveTo(position) {
if (position < 0 || position > this.listSize - 1) {
return false
}
this.pos = position
return true
}
// 获取当前元素
getElement() {
return this.dataStore[this.pos]
}
// 判断是否有后一位,我个人感觉这个方法语义上有问题,已经到列表的最后一位了,为什么hasNext还会返回true。但是这个我没改正,因为改正之后发现不能使用迭代器了。所以可能原书的方法是没问题的,是我想的有问题。
hasNext() {
return this.pos < this.listSize
}
// 判断是否有前一位 原书的方法,个人感觉有问题,为什么明明都是第一位了,hasPrev还是为true。唯一能想到的理由就是为了遍历。所以不订正了,使用原程序
hasPrev(){
return this.pos >=0
}
}
对列表进行测试,这个章节在原书中也非常简略,感觉作者有点缺乏诚意。
// 初始化一个列表
let names = new List()
// 调用append方法
names.append('a')
names.append('b')
names.append('c')
console.log(names.length) // 3
// 调用remove方法
names.remove('b')
console.log(names.length) // 2
// 调用toString方法
console.log(names.toString()) // ["a", "c"]
// 调用insert方法
names.insert('d', 'c')
console.log(names.toString()) // ["a", "c", "d"]
// 调用contains方法
console.log(names.contains('b')) // false
console.log(names.contains('f')) // flase
// 调用end方法,将位置一定到最后一位
names.end()
console.log(names.getElement()) // d
// 调用currPos方法获取位置
console.log(names.currPos()) // 2
// 调用hasNext方法,判断是否还有后一位
console.log(names.hasNext()) // true
// 调用hasPrev方法,判断是否还有前一位
console.log(names.hasPrev()) // true
// 调用front方法,将位置移动到首位
names.front()
console.log(names.getElement()) // a
// 调用currPos方法获取位置
console.log(names.currPos()) // 0
// 调用hasNext方法,判断是否还有后一位
console.log(names.hasNext()) // true
// 调用hasPrev方法,判断是否还有前一位
console.log(names.hasPrev()) // true
// 调用next方法,向后移动一位
console.log(names.getElement()) // a
names.next()
console.log(names.getElement()) // c
// 调用prev方法,向前移动一位
console.log(names.getElement()) // c
names.prev()
console.log(names.getElement()) // a
3.3 使用迭代器访问列表
正序迭代器
for (names.front(); names.hasNext(); names.next()) {
console.log(names.getElement())
}
// a c d
倒序迭代器
for (names.end(); names.hasPrev(); names.prev()) {
console.log(names.getElement())
}
// d c a
3.4 一个基于列表的应用
书中给了一个使用列表的案例——用列表存储电影名,然后对列表进行添加、删除、遍历等操作。类似案例可以是图书书目、音乐列表等。因为案例很简单,3.2节对列表进行测试的时候,列表的方法我都已经测过了,所以不再贴出来书上的案例了。
个人点评:列表对于前端工程师来说是一个新的概念。做前端的人,大部分都用不到列表这个数据结构,数组似乎就可以搞定一切。为什么要搞一个列表的感念呢,我个人暂时也不清楚,大概是为了交流方便把。比如数组在不同的语言有不同的表现,但是列表就要求,可能不同的语言都要统一一种实现方式。
另外原书中的代码有很多不严谨或者不正确的地方,也有很多做法跟我想得不一样的地方。也不知道对还是错,现在也评估不出来。欢迎小伙伴交流沟通。