js实现链表结构

110 阅读2分钟

简介

本文基于理解JavaScript中的数据结构(链表)一文,进行改造完善。对于对应方法的理解可参考该文中的图解。

实现的链表方法和属性

  • headNode: 头节点
  • endNode: 尾节点
  • length: 长度
  • append(val): 末尾添加值
  • preAppend(val): 链表开头添加值
  • getIndexVal(index): 根据索引查询值
  • insert(val, index): 插入
  • remove(index): 删除
  • reverse(): 反转

声明节点类及链表类

class Node {
  constructor(val) {
    this.val = val;
    this.next = null;
  }
}
class LinkedList {
  constructor() {
    /** 初始值头节点 */
    this.headNode = null;
    /** 初始值尾节点 */
    this.endNode = null;
    /** 初始值长度 */
    this.length = 0;
  }
}

工具方法

/**
 * 得指定index node和前一个node
 * @param {*} index 当前index
 * @param {*} that 对象实例
 * @returns 
 */
static getPreAndCurrent(index, that) {
  let preNode = null;
  let currNode = null;
  if (index <= that.length) {
    if (index !== 0) {
      preNode = that.getIndexVal(index - 1);
    }
    currNode = that.getIndexVal(index);
  }
  return {
    preNode,
    currNode,
  };
}
/**
 * 超界
 * @param {*} index 当前index
 * @param {*} that 对象实例
 */
static IndexOut(index, that) {
  if (index < 0 || index >= that.length) {
    throw new Error("下标超出");
  }
}

功能方法

  append(val) {
    const node = new Node(val);
    /**
     * 链表为空时,头和尾都是当前添加的node
     * 链表不为空时,尾节点添加next为当前节点,然后设置新的尾节点尾当期节点
     */
    if (!this.headNode) {
      this.headNode = node;
      this.endNode = node;
    } else {
      this.endNode.next = node;
      this.endNode = node;
    }
    this.length++;
  }
  preAppend(val) {
    const node = new Node(val);
    node.next = this.headNode;
    this.headNode = node;
    this.length++;
  }
  /**
   * 根据索引的值
   */
  getIndexVal(index) {
    let count = 0;
    let currentNode = this.headNode;
    while (count < index) {
      currentNode = currentNode.next;
      count++;
    }
    return currentNode;
  }
  /** 插入 */
  insert(val, index) {
    if (index >= this.length) {
      this.append(val);
    } else {
      const node = new Node(val);
      const { preNode, currNode } = LinkedList.getPreAndCurrent(index, this);
      if (index === 0) {
        this.headNode = node;
      } else {
        preNode.next = node;
      }
      node.next = currNode;
      this.length++;
    }
  }
  /** 删除 */
  remove(index) {
    LinkedList.IndexOut(index, this);
    const { preNode } = LinkedList.getPreAndCurrent(index, this);
    const nextNode = this.getIndexVal(index + 1);
    if (index === 0) {
      this.headNode = nextNode;
    } else {
      preNode.next = nextNode;
    }
    this.length--;
    /** index为之前的被删除的,this.length已经--,现在this.length等于传入的index */
    if (index === this.length) {
      /** 取新链表的最后一个 */
      this.endNode = this.getIndexVal(this.length - 1);
    }
  }
  /** 反转 */
  reverse() {
    let previousNode = null;
    let currentNode = this.headNode;

    while (currentNode !== null) {
      let nextNode = currentNode.next;
      currentNode.next = previousNode;
      previousNode = currentNode;
      currentNode = nextNode;
    }

    this.headNode = previousNode;
  }

完整代码

class Node {
  constructor(val) {
    this.val = val;
    this.next = null;
  }
}

class LinkedList {
  constructor() {
    this.headNode = null;
    this.endNode = null;
    this.length = 0;
  }

  static getPreAndCurrent(index, that) {
    let preNode = null;
    let currNode = null;
    if (index <= that.length) {
      if (index !== 0) {
        preNode = that.getIndexVal(index - 1);
      }
      currNode = that.getIndexVal(index);
    }
    return {
      preNode,
      currNode,
    };
  }

   /**
   * 超界
   * @param {*} index 当前index
   * @param {*} that 对象实例
   */
    static IndexOut(index, that) {
      if (index < 0 || index >= that.length) {
        throw new Error("下标超出");
      }
    }

  append(val) {
    const node = new Node(val);
    /**
     * 链表为空时,头和尾都是当前添加的node
     * 链表不为空时,尾节点添加next为当前节点,然后设置新的尾节点尾当期节点
     */
    if (!this.headNode) {
      this.headNode = node;
      this.endNode = node;
    } else {
      this.endNode.next = node;
      this.endNode = node;
    }
    this.length++;
  }

  preAppend(val) {
    const node = new Node(val);
    node.next = this.headNode;
    this.headNode = node;
    this.length++;
  }

  /**
   * 根据索引的值
   */
  getIndexVal(index) {
    let count = 0;
    let currentNode = this.headNode;
    while (count < index) {
      currentNode = currentNode.next;
      count++;
    }
    return currentNode;
  }

  /** 插入 */
  insert(val, index) {
    if (index >= this.length) {
      this.append(val);
    } else {
      const node = new Node(val);
      const { preNode, currNode } = LinkedList.getPreAndCurrent(index, this);
      if (index === 0) {
        this.headNode = node;
      } else {
        preNode.next = node;
      }
      node.next = currNode;
      this.length++;
    }
  }

  /** 删除 */
  remove(index) {
    LinkedList.IndexOut(index, this);
    const { preNode } = LinkedList.getPreAndCurrent(index, this);
    const nextNode = this.getIndexVal(index + 1);
    if (index === 0) {
      this.headNode = nextNode;
    } else {
      preNode.next = nextNode;
    }
    this.length--;
    /** index为之前的被删除的,this.length已经--,现在this.length等于传入的index */
    if (index === this.length) {
      /** 取新链表的最后一个 */
      this.endNode = this.getIndexVal(this.length - 1);
    }
  }

  /** 反转 */
  reverse() {
    let previousNode = null;
    let currentNode = this.headNode;

    while (currentNode !== null) {
      let nextNode = currentNode.next;
      currentNode.next = previousNode;
      previousNode = currentNode;
      currentNode = nextNode;
    }

    this.headNode = previousNode;
  }
}

const testLinked = new LinkedList();
testLinked.append(2);
testLinked.append(4);
testLinked.preAppend(1);
testLinked.insert("insert", 4);
testLinked.remove(2);
console.log(testLinked);
console.log(testLinked.getIndexVal(3), testLinked.endNode);

个人博客

个人博客

参考文章

理解JavaScript中的数据结构(链表)