数据结构与算法Javascript描述-(1~9章)

390 阅读7分钟

数据结构与算法Javascript描述

之前翻完了 <<数据结构与算法Javascript描述>> 这本书,现在梳理下学习到的内容和收获,以便更深入理解与记忆。

目录结构

第一章 Javascript的编程环境和模型

本章主要交代了JS的运行环境及基础语法,如变量,运算,判断,循环结构,函数及作用域,递归。主要是为后面的数据结构及算法提供基础知识。

  1. 目录结构

  1. 要点
  • JS中,函数的参数传递方式都是按值传递,没有按引用传递的参数。但是JS中有保存引用的对象,比如数组,他们是按引用传递的。

  • 变量作用域是指一个变量在程序中的哪些地方可以访问。JS中的变量作用域被定义为函数作用域。这是指变量的值在定义该变量的函数内是可见的,并且定义在该函数内的嵌套函数中也可以访问该变量。

  • 任何可以被递归定义的函数,都可以被改写为迭代式(动态规划)的程序

  • 编写出容易阅读的代码和编写出让计算机正确执行的代码同等重要。

第二章 数组

数组的标准定义是:一个存储元素的线性集合,元素可以通过索引来任意存取,索引通常是数字,用来计算元素之间存储位置的偏移量。

  1. 目录结构

  1. 要点

本章主要介绍了数组的概念和操作数组的相关方法,包括数组的读写,索引,队列,迭代,排序等。

第三章 列表

列表是一组有序(排列顺序)的数据

  1. 目录结构

  1. 列表实现
属性及方法描述
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)的数据结构。对栈的两种主要操作是将一个元素压入栈和将一个元素弹出栈。

  1. 目录结构

  1. 栈实现
属性及方法描述
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;
    }
}
  1. 栈应用
  • 数制间的相互转换

  • 回文

  • 递归(阶乘)

第五章 队列

队列是一种特殊的列表,队列只能在队尾插入元素,在队首删除元素。队列是一种先进先出(FIFO First-In-First-Out)的数据结构。队列的主要操作是向队列中插入新元素和删除队列中的元素,即入队和出队。

  1. 目录结构

  1. 队列实现
属性及方法描述
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 = [];
    }
}
  1. 应用
  • 舞伴分配

  • 数据排序(基数排序)

  • 优先队列(排队)

第六章 链表

链表是由一组节点组成的集合。每个节点都使用一个对象的引用指向它的后继。指向另一个节点的引用叫做链。数组元素靠位置进行引用,链表靠相互之间的关系进行引用。

  1. 目录结构

  1. 为什么使用链表?

在许多编程语言中数组长度是固定的,当添加和删除元素时需要将其它元素都向前或向后平移,效率低下。JS的数组被设计为对象,不会有同样的问题,但是效率比其它语言低很多。而在链表中,只需要更改部分元素的引用关系即可,更加高效快速。

  1. 链表实现
属性及方法描述
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;
        }
    }
}
  1. 双向链表

所有节点添加 previous 属性指向前节点,头节点的 previousnull,可以实现从后向前的遍历。

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;
        }

    }
}
  1. 循环链表

最后一个节点指向 head 节点

class circuLinkedList {
    constructor() {
        this.head = new Node('head');
        this.head.next = this.head;
    }
}

第七章 字典

字典是一种以 键-值 对形式存储数据的数据结构。Dictionary类的基础是Array类。

  1. 目录结构

  1. 字典实现
属性及方法描述
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)
    }
}

第八章 散列

散列使用的数据结构叫做散列表。碰撞指的是散列表的索引对应多个不同的键值(数据)。

  1. 目录结构

  1. 散列实现
属性及方法描述
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. 碰撞处理
  • 开链法

散列表的索引不再对应单一数值,而是对应键值数组。

  • 线性探测法

当散列表的索引已有数据,则将索引(+1)再判断是否有数据,直到新索引没有数据则存储。

第九章 集合

集合(Set)是一种包含不同元素的数据结构。

  • 集合中的成员是无序的

  • 集合不允许相同成员存在

  1. 目录结构

  1. 相关概念
  • 并集 将两个集合中的成员进行合并,得到一个新集合

  • 交集 两个集合共同存在的成员组成一个新集合

  • 补集 属于一个集合而不属于另一个集合的成员组成的集合

  1. 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