JS数据结构学习(1)

161 阅读3分钟

一维数据结构(线性数据结构)

💡 Tips:操作系统小知识:通过偏移查询数据性能最好。

数组的特性:

  • 存储在物理空间是连续的。
  • 底层的数组长度是不可变的。
  • 数组的变量,指向数组的第一个元素的位置。

优点:查询性能好。

缺点:

  • 空间必须是连续的,当数组空间较大,且当系统中空间碎片较多的时候,容易存放不下。
  • 长度是固定的,数组是难以被添加(可能需要扩容数组大小)和删除(可能需要将所删除元素位置后面的所有元素往前移动)的

优化:

  • 创建数组时,在知道数组长度的情况下,使用new Array(10)的方式来固定数组的长度

数组总结:

  1. 数组的内存存储是连续的,受空间碎片的影响,数组内存较大的时候,容易存不下
  2. 数组查询性能较好
  3. 数组的受固定长度的影响,新增和删除的性能较差

链表(Linked-list)

💡 Tips:

链表的特点:

  • 空间是不连续的
  • 每存一个值,就会多开销一个引用空间

优点:

  • 只要内存够大,就能存的下,不受空间碎片的影响
  • 链表的删除和添加比较容易

缺点:

  • 查询速度慢(查询某个位置)
  • 每个创建的节点都需要创建一个next指向,浪费空间

链表总结:

  1. 链表在内存中存储不是连续的,所以不受内存碎片的影响
  2. 链表查询速度较慢(需从表头开始查询)
  3. 链表新增和删除的性能较好

链表基础操作示例:




class node {
  value: any
  next?: node | null
  constructor(value: any, next: node | null = null) {

    this.value = value;
    this.next = next;
  }
}

/**
 * 1.初始化链表
 * 2.打印链表所有节点
 * 3.链表插入到某个节点之前
 * 4.链表插入到某个节点之后
 * 5.链表删除某个节点
 * 6.链表查找某个节点
 */

/**
 * 链表
 */
class LinkedList {
  private head: node

  /**
   * 初始化链表
   * @param value 
   * @param next 
   */

  constructor(value: any, next: node | null) {
    this.head = new node(value, next);
  }

  /**
   * 打印链表所有节点
   * @returns void
   */
  traverse(): void {
    let root = this.head;
    console.log(root.value);
    while (root.next) {
      root = root.next;
      console.log(root.value);
    }
  }

  /**
   * 根据节点值来查询节点
   * @param value 
   * @returns 返回查询出的节点
   */
  search(value: any): node {
    if (!this.head) return;

    let root = this.head;
    while (root) {
      if (root.value === value) {
        return root;
      }
      root = root.next;
    }
    return root;
  }

  /**
   * 删除链表第一个节点
   * @returns 删除删除的节点
   */
  shift(): node {
    const cur = this.head;
    this.head = this.head.next
    return cur
  }

  /**
  * 删除链表最后一个节点
  * @returns 返回删除的节点
  */
  pop(): node {
    let pre = null;
    let cur = this.head;
    while (cur && cur.next) {
      pre = cur;
      cur = cur.next;
    }

    pre.next = null;
    return pre;
  }

  /**
   * 获取最后一个节点
   * @returns 返回最后一个节点
   */
  private getLastNode(): node {
    let cur = this.head;
    while (cur.next) {
      cur = cur.next;
    }
    return cur
  }

  /**
   * 插入一个节点到链表最后
   * @param value 
   * @returns 返回添加的节点
   */
  push(value: any): node {
    const newNode = new node(value);
    let cur = this.getLastNode();
    cur.next = newNode;
    return cur;
  }

  /**
   * 在链表头部插入一个节点
   * @param value 
   * @returns 返回新添加的节点
   */
  unshift(value: any): node {
    const newNode = new node(value)
    newNode.next = this.head;

    this.head = newNode
    return newNode;
  }


  /**
   * 插入一个节点
   * @param insertNodeValue 
   * @param insertNodeAfter 插入到哪一个值之后
   */
  insertAfter(insertNodeValue: any, insertNodeAfter: any) {
    const newNode = new node(insertNodeValue)
    let cur = this.head;
    while (cur && cur.value !== insertNodeAfter) {
      cur = cur.next;
    }

    if (cur) {
      // 存储的是地址
      let next = cur.next;

      cur.next = newNode;
      newNode.next = next;
    }
  }

  /**
   * 插入一个节点
   * @param insertNodeValue 
   * @param insertNodeBefore 插入到哪一个值之后
   */
  insertBefore(insertNodeValue: any, insertNodeBefore: any) {
    const newNode = new node(insertNodeValue)
    let cur = this.head;
    let pre = null;
    while (cur && cur.value !== insertNodeBefore) {
      pre = cur;
      cur = cur.next;
    }
    if (cur && !pre) {
      // 这种情况可能是只有一个节点
      this.unshift(insertNodeValue)
    } else if (cur) {
      // 存储的是地址
      pre.next = newNode;
      newNode.next = cur;
    }
  }

  /**
   * 删除对应值的节点(一次仅能删除一个)
   * @param value 
   * @returns 返回删除的节点
   */
  delete(value: any) {

    let cur = this.head;
    if (!cur) return;

    // 删除第一个节点
    if (cur && cur.value === value) {
      this.head = cur.next;
      return cur;
    }

    let pre = null;
    while (cur.next && cur.value !== value) {
      pre = cur;
      cur = cur.next;
    }

    // 有所需删除的节点
    if (cur) {
      pre.next = cur.next;
    }

    return cur;
  }

  /**
   * 链表逆序
   */
  reserve() {
    let pre = null;
    let cur = this.head;
    while (cur) {
      let next = cur.next;
      cur.next = pre;

      pre = cur;
      cur = next;
    }
    this.head = pre;
  }
}

const LinkList = new LinkedList(1, null)
LinkList.push(2)
LinkList.push(3)
LinkList.push(4)
LinkList.push(5)
LinkList.insertBefore(6, 1)

LinkList.reserve()
LinkList.traverse();