数据结构与算法Javascript描述
之前翻完了 <<数据结构与算法Javascript描述>> 这本书,现在梳理下学习到的内容和收获,以便更深入理解与记忆。
目录结构
第一章 Javascript的编程环境和模型
本章主要交代了JS的运行环境及基础语法,如变量,运算,判断,循环结构,函数及作用域,递归。主要是为后面的数据结构及算法提供基础知识。
- 目录结构
- 要点
-
JS中,函数的参数传递方式都是按值传递,没有按引用传递的参数。但是JS中有保存引用的对象,比如数组,他们是按引用传递的。
-
变量作用域是指一个变量在程序中的哪些地方可以访问。JS中的变量作用域被定义为函数作用域。这是指变量的值在定义该变量的函数内是可见的,并且定义在该函数内的嵌套函数中也可以访问该变量。
-
任何可以被递归定义的函数,都可以被改写为迭代式(动态规划)的程序
-
编写出容易阅读的代码和编写出让计算机正确执行的代码同等重要。
第二章 数组
数组的标准定义是:一个存储元素的线性集合,元素可以通过索引来任意存取,索引通常是数字,用来计算元素之间存储位置的偏移量。
- 目录结构
- 要点
本章主要介绍了数组的概念和操作数组的相关方法,包括数组的读写,索引,队列,迭代,排序等。
第三章 列表
列表是一组有序(排列顺序)的数据
- 目录结构
- 列表实现
| 属性及方法 | 描述 |
|---|---|
| listSize | 列表的元素个数 |
| pos | 列表的当前位置 |
| length | 返回列表中元素的个数 |
| clear | 清空列表中所有元素 |
| getElement | 返回当前位置的元素 |
| insert | 在现有元素后插入新元素 |
| append | 在列表的末尾添加新元素 |
| remove | 从列表中删除元素 |
| front | 将列表的当前位置移动到第一个元素 |
| end | 将列表的当前位置移动到最后一个元素 |
| prev | 将当前位置后移一位 |
| next | 将当前位置前移一位 |
| hasNext | 判断后一位 |
| hasPrev | 判断前一位 |
| moveTo | 将当前位置移动到指定位置 |
class List {
constructor() {
this.listSize = 0;
this.pos = 0;
this.dataStore = [];
}
clear() {
this.listSize = this.pos = 0;
this.dataStore = [];
}
find(element) {
for (let i = 0; i < this.listSize; i++) {
if (this.dataStore[i] === element) {
return i;
}
}
return -1;
}
contains(element) {
const foundAt = this.find(element);
if (foundAt > -1) {
return true;
}
return false;
}
insert(element, after) {
const insertPos = this.find(after);
if (insertPos > -1) {
this.dataStore.splice(insertPos + 1, 0, element);
this.listSize++;
return true;
}
return false;
}
append(element) {
this.dataStore[this.listSize++] = element;
}
remove(element) {
const foundAt = this.find(element) > -1;
if (foundAt > -1) {
this.dataStore.splice(i, 1);
this.listSize--;
return true;
}
return false;
}
front() {
this.pos = 0;
}
end() {
this.pos = this.listSize - 1;
}
prev() {
if (this.pos) {
this.pos--;
}
}
next() {
if (this.pos < this.listSize - 1) {
this.pos++;
}
}
hasNext() {
return this.pos < this.listSize - 1;
}
hasPrev() {
return this.pos > 0;
}
moveTo(position) {
this.pos = position;
}
getElement() {
return this.dataStore[this.pos];
}
}
第四章 栈
栈是一种特殊的列表,栈内的元素只能通过列表的一端访问,这一端称为栈顶。栈被称为一种后入先出(LIFO last-in-first-out)的数据结构。对栈的两种主要操作是将一个元素压入栈和将一个元素弹出栈。
- 目录结构
- 栈实现
| 属性及方法 | 描述 |
|---|---|
| top | 栈索引(长度) |
| push | 入栈 |
| pop | 出栈 |
| clear | 清空栈 |
| peek | 返回栈顶元素 |
class Stack {
constructor() {
this.top = 0;
this.dataStore = [];
}
pop() {
return this.dataStore[--this.top];
}
push(element) {
this.dataStore[this.top++] = element;
}
peek() {
return this.dataStore[this.top - 1];
}
clear() {
this.top = 0;
}
}
- 栈应用
-
数制间的相互转换
-
回文
-
递归(阶乘)
第五章 队列
队列是一种特殊的列表,队列只能在队尾插入元素,在队首删除元素。队列是一种先进先出(FIFO First-In-First-Out)的数据结构。队列的主要操作是向队列中插入新元素和删除队列中的元素,即入队和出队。
- 目录结构
- 队列实现
| 属性及方法 | 描述 |
|---|---|
| push | 添加元素 |
| shift | 移除元素 |
| clear | 清空队列 |
| front | 返回队首元素 |
| back | 返回队尾元素 |
class Queue {
constructor() {
this.dataStore = [];
}
shift() {
return this.dataStore.shift();
}
push(element) {
this.dataStore.push(element);
}
front() {
return this.dataStore[0];
}
back() {
return this.dataStore[this.dataStore.length - 1];
}
clear() {
this.dataStore = [];
}
}
- 应用
-
舞伴分配
-
数据排序(基数排序)
-
优先队列(排队)
第六章 链表
链表是由一组节点组成的集合。每个节点都使用一个对象的引用指向它的后继。指向另一个节点的引用叫做链。数组元素靠位置进行引用,链表靠相互之间的关系进行引用。
- 目录结构
- 为什么使用链表?
在许多编程语言中数组长度是固定的,当添加和删除元素时需要将其它元素都向前或向后平移,效率低下。JS的数组被设计为对象,不会有同样的问题,但是效率比其它语言低很多。而在链表中,只需要更改部分元素的引用关系即可,更加高效快速。
- 链表实现
| 属性及方法 | 描述 |
|---|---|
| display | 显示链表元素 |
| find | 查找元素 |
| insert | 添加元素 |
| remove | 删除元素 |
class Node {
constructor(element) {
this.element = element;
this.next = null;
}
}
class LinkedList {
constructor() {
this.head = new Node('head');
}
find(item) {
let curNode = this.head;
while(curNode) {
if (curNode.element === item) {
break;
}
curNode = curNode.next;
}
return curNode;
}
insert(newElement, itme) {
const newNode = new Node(newElement);
const curNode = this.find(itme);
newNode.next = curNode.next;
curNode.next = newNode;
}
findPrevious(item) {
let curNode = this.head;
while(curNode) {
if (curNode.next && curNode.next.element === item) {
break;
}
curNode = curNode.next;
}
return curNode;
}
remove(item) {
const prevNode = this.findPrevious(item);
if (prevNode.next !== null) {
prevNode.next = prevNode.next.next;
}
}
display() {
let curNode = this.head;
while(curNode) {
console.log(curNode.element);
curNode = curNode.next;
}
}
}
- 双向链表
所有节点添加 previous 属性指向前节点,头节点的 previous 为 null,可以实现从后向前的遍历。
class Node {
constructor(element) {
this.element = element;
this.previous = null;
this.next = null;
}
}
class twoWayLinkedList {
constructor() {
this.head = new Node('head');
}
find() {
let curNode = this.head;
while(curNode) {
if (curNode.element === item) {
break;
}
curNode = curNode.next;
}
return curNode;
}
insert(newElement, itme) {
const newNode = new Node(newElement);
const curNode = this.find(itme);
newNode.next = curNode.next;
newNode.previous = curNode;
curNode.next = newNode;
}
remove(item) {
const curNode = this.find(item);
if (curNode.next !== null) {
curNode.previous.next = curNode.next;
curNode.next.previous = curNode.previous;
}
}
findLast() {
let curNode = this.head;
while(curNode) {
curNode = curNode.next;
}
return curNode;
}
displayReverse() {
let curNode = this.findLast();
while(curNode) {
console.log(curNode.element);
curNode = curNode.previous;
}
}
}
- 循环链表
最后一个节点指向 head 节点
class circuLinkedList {
constructor() {
this.head = new Node('head');
this.head.next = this.head;
}
}
第七章 字典
字典是一种以 键-值 对形式存储数据的数据结构。Dictionary类的基础是Array类。
- 目录结构
- 字典实现
| 属性及方法 | 描述 |
|---|---|
| showAll | 显示字典 |
| find | 查找字典 |
| add | 添加字典 |
| remove | 删除字典 |
| count | 计算字典长度(以字符串为key的数组不能使用length) |
class Dictionary {
constructor() {
this.dataStore = [];
}
add(key, value) {
this.dataStore[key] = value;
}
find(key) {
return this.dataStore[key];
}
remove(key) {
delete this.dataStore[key];
}
showAll() {
Object.keys(this.dataStore).forEach((key) => {
console.log(this.dataStore[key]);
}, this)
}
count() {
Object.keys(this.dataStore).forEach((key) => {
delete this.dataStore[key];
}, this)
}
}
第八章 散列
散列使用的数据结构叫做散列表。碰撞指的是散列表的索引对应多个不同的键值(数据)。
- 目录结构
- 散列实现
| 属性及方法 | 描述 |
|---|---|
| simpleHash | 散列函数 |
| get | 查找散列 |
| put | 添加散列 |
| showDistro | 显示散列 |
- 散列函数
function simpleHash(data) {
let total = 0;
for (let i = 0, len = data.length; i < len; i++) {
total += data.charCodeAt(i);
}
// 散列方式:除留余数法
return total % this.table.length;
}
- 更好的散列函数(减少碰撞)(霍纳算法)
function betterHash() {
// 质数
const H = 37;
for (let i = 0, len = data.length; i < len; i++) {
total += (H * total) + data.charCodeAt(i);
}
// 散列方式:除留余数法
return total % this.table.length;
}
- 散列类
class HashTable {
constructor() {
this.table = new Array(137);
this.simpleHash = simpleHash;
}
put(data) {
const pos = this.simpleHash(data);
this.table[pos] = data;
}
get(data) {
return this.table[this.simpleHash(data)]
}
showDistro() {
this.table.forEach((item) => {
if (item !== undefined) {
console.log(item);
}
});
}
}
- 碰撞处理
- 开链法
散列表的索引不再对应单一数值,而是对应键值数组。
- 线性探测法
当散列表的索引已有数据,则将索引(+1)再判断是否有数据,直到新索引没有数据则存储。
第九章 集合
集合(Set)是一种包含不同元素的数据结构。
-
集合中的成员是无序的
-
集合不允许相同成员存在
- 目录结构
- 相关概念
-
并集 将两个集合中的成员进行合并,得到一个新集合
-
交集 两个集合共同存在的成员组成一个新集合
-
补集 属于一个集合而不属于另一个集合的成员组成的集合
- Set类的实现
| 属性及方法 | 描述 |
|---|---|
| show | 显示集合 |
| find | 查找元素 |
| add | 添加元素 |
| remove | 删除元素 |
| contains | 判断是否包含元素 |
| union | 并集 |
| intersect | 交集 |
| difference | 补集 |
class Set {
constructor() {
this.dataStore = [];
}
add() {
if (this.dataStore.indexOf(data) === -1) {
this.dataStore.push(data);
return true;
} else {
return false;
}
}
remove() {
const pos = this.dataStore.indexOf(data);
if (pos > -1) {
this.dataStore.splice(pos, 1);
return true;
} else {
return false;
}
}
show() {
return this.dataStore;
}
contains() {
if (this.dataStore.indexOf(data) > -1) {
return true;
} else {
return false;
}
}
union(set) {
const tempSet = new Set();
for (let i =0, len = this.dataStore.length; i < tlen; i++) {
tempSet.add(this.dataStore[i]);
}
for (let i = 0, len = this.dataStore.length; i < len; i++) {
if (!tempSet.contains(set.dataStore[i])) {
tempSet.dataStore.push(set.dataStore);
}
}
}
intersect(set) {
const tempSet = new Set();
for (let i = 0, len = this.dataStore.length; i < len; i++) {
if (set.contains(this.dataStore[i])) {
tempSet.add(this.dataStore[i]);
}
}
return tempSet;
}
difference(set) {
const tempSet = new Set();
for (let i = 0; i < this.dataStore.length; i++) {
if (!set.contains(this.dataStore[i])) {
tempSet.add(this.dataStore[i])
}
}
return tempSet;
}
}
其它章节内容
因为其它章节的内容比较丰富,所以写成单独的笔记
欢迎到前端自习群一起学习~516913974