1、双向链表

双向链表 (doulby linked list) 是一个线性数据结构,表示一组元素,每个元素都指向下一个和上一个元素。双向链表中的第一个元素是头 (head),最后一个元素是尾 (tail)。

  • 双向链表数据结构的每个元素都必须具有以下属性:
    • value: 元素的值
    • next: 指向链表中下一个元素的指针(如果没有,则为 null)
    • previous: 指向链表中前一个元素的指针(如果没有,则为 null)
  • 双向链表数据结构的主要属性是:
    • size: 双向链表中元素的数量
    • head: 双向链表的第一个元素
    • tail: 双向链表的最后一个元素
  • 双向链表数据结构的主要操作是:

    • insertAt: 在特定索引处插入一个元素
    • removeAt: 删除特定索引处的元素
    • getAt: 检索特定索引处的元素
    • clear: 清空双向链表
    • reverse: 颠倒双向链表中元素的顺序 ```javascript class DoublyLinkedList { constructor() { this.nodes = []; }

    get size() { return this.nodes.length; }

    get head() { return this.size ? this.nodes[0] : null; }

    get tail() { return this.size ? this.nodes[this.size - 1] : null; }

    insertAt(index, value) { const previousNode = this.nodes[index - 1] || null; const nextNode = this.nodes[index] || null; const node = { value, next: nextNode, previous: previousNode };

    if (previousNode) previousNode.next = node; if (nextNode) nextNode.previous = node; this.nodes.splice(index, 0, node); }

    insertFirst(value) { this.insertAt(0, value); }

    insertLast(value) { this.insertAt(this.size, value); }

    getAt(index) { return this.nodes[index]; }

    removeAt(index) { const previousNode = this.nodes[index - 1] || null; const nextNode = this.nodes[index + 1] || null;

    if (previousNode) previousNode.next = nextNode; if (nextNode) nextNode.previous = previousNode;

    return this.nodes.splice(index, 1); }

    clear() { this.nodes = []; }

    reverse() { this.nodes = this.nodes.reduce((acc, { value }) => {

    1. const nextNode = acc[0] || null;
    2. const node = { value, next: nextNode, previous: null };
    3. if (nextNode) nextNode.previous = node;
    4. return [node, ...acc];

    }, []); }

    Symbol.iterator { yield this.nodes; } } ```

    2、树

    树是一种数据结构,由一组表示分层树结构的链接节点组成。每个节点通过父子关系链接到其他节点。树中的第一个节点是根,而没有子节点的节点是叶子。

  • 树数据结构中的每个节点必须具有以下属性:

    • key: 节点的key值
    • value: 节点的value值
    • parent: 节点的父节点(如果没有,则为 null)
    • children: 指向节点子节点的指针数组
  • 树型数据结构的主要操作是:

    • insert: 将节点作为给定父节点的子节点插入
    • remove: 从树中移除节点及其子节点
    • find: 检索给定的节点
    • preOrderTraversal: 前序遍历,通过递归遍历树中的每个节点及其子节点来遍历树
    • postOrderTraversal: 后序遍历,通过递归遍历每个节点的子节点后面跟着节点来遍历树 ```javascript class TreeNode { constructor(key, value = key, parent = null) { this.key = key; this.value = value; this.parent = parent; this.children = []; }

    get isLeaf() { return this.children.length === 0; }

    get hasChildren() { return !this.isLeaf; } }

class Tree { constructor(key, value = key) { this.root = new TreeNode(key, value); }

preOrderTraversal(node = this.root) { yield node; if (node.children.length) { for (let child of node.children) { yield this.preOrderTraversal(child); } } }

postOrderTraversal(node = this.root) { if (node.children.length) { for (let child of node.children) { yield this.postOrderTraversal(child); } } yield node; }

insert(parentNodeKey, key, value = key) { for (let node of this.preOrderTraversal()) { if (node.key === parentNodeKey) { node.children.push(new TreeNode(key, value, node)); return true; } } return false; }

remove(key) { for (let node of this.preOrderTraversal()) { const filtered = node.children.filter(c => c.key !== key); if (filtered.length !== node.children.length) { node.children = filtered; return true; } } return false; }

find(key) { for (let node of this.preOrderTraversal()) { if (node.key === key) return node; } return undefined; } } ```