append(element)
向链表尾部追加一个新元素。insert(position, element)
向链表的指定位置插入一个新元素。getElement(position)
获取指定位置的元素。indexOf(element)
返回元素在链表中的索引。如果链表中没有该元素就返回 -1。update(position, element)
修改指定位置上的元素。removeAt(position)
从链表中的删除指定位置的元素。remove(element)
从链表删除指定的元素。isEmpty()
如果链表中不包含任何元素,返回 trun
,如果链表长度大于 0 则返回 false
。size()
返回链表包含的元素个数,与数组的 length
属性类似。toString()
由于链表项使用了 Node 类,就需要重写继承自 JavaScript 对象默认的 toString
方法,让其只输出元素的值。forwardString()
返回正向遍历节点字符串形式。backwordString()
返回反向遍历的节点的字符串形式。this.prev
属性,该属性用于指向上一个节点。this.tail
属性,该属性指向末尾的节点。// 双向链表的节点类(继承单向链表的节点类)class DoublyNode extends Node {constructor(element) {super(element);this.prev = null;}}// 双向链表类继承单向链表类class DoublyLinkedList extends LinkedList {constructor() {super();this.tail = null;}}
// append(element) 往双向链表尾部追加一个新的元素// 重写 append()append(element) {// 1、创建双向链表节点const newNode = new DoublyNode(element);// 2、追加元素if (this.head === null) {this.head = newNode;this.tail = newNode;} else {// !!跟单向链表不同,不用通过循环找到最后一个节点// 巧妙之处this.tail.next = newNode;newNode.prev = this.tail;this.tail = newNode;}this.length++;}
// insert(position, data) 插入元素// 重写 insert()insert(position, element) {// 1、position 越界判断if (position < 0 || position > this.length) return false;// 2、创建新的双向链表节点const newNode = new DoublyNode(element);// 3、判断多种插入情况if (position === 0) { // 在第 0 个位置插入if (this.head === null) {this.head = newNode;this.tail = newNode;} else {//== 巧妙之处:相处腾出 this.head 空间,留个 newNode 来赋值 ==//newNode.next = this.head;this.head.perv = newNode;this.head = newNode;}} else if (position === this.length) { // 在最后一个位置插入this.tail.next = newNode;newNode.prev = this.tail;this.tail = newNode;} else { // 在 0 ~ this.length 位置中间插入let targetIndex = 0;let currentNode = this.head;let previousNode = null;// 找到要插入位置的节点while (targetIndex++ < position) {previousNode = currentNode;currentNode = currentNode.next;}// 交换节点信息previousNode.next = newNode;newNode.prev = previousNode;newNode.next = currentNode;currentNode.prev = newNode;}this.length++;return true;}
// insert(position, data) 插入元素// 重写 insert()insert(position, element) {// 1、position 越界判断if (position < 0 || position > this.length) return false;// 2、创建新的双向链表节点const newNode = new DoublyNode(element);// 3、判断多种插入情况if (position === 0) { // 在第 0 个位置插入if (this.head === null) {this.head = newNode;this.tail = newNode;} else {//== 巧妙之处:相处腾出 this.head 空间,留个 newNode 来赋值 ==//newNode.next = this.head;this.head.perv = newNode;this.head = newNode;}} else if (position === this.length) { // 在最后一个位置插入this.tail.next = newNode;newNode.prev = this.tail;this.tail = newNode;} else { // 在 0 ~ this.length 位置中间插入let targetIndex = 0;let currentNode = this.head;let previousNode = null;// 找到要插入位置的节点while (targetIndex++ < position) {previousNode = currentNode;currentNode = currentNode.next;}// 交换节点信息previousNode.next = newNode;newNode.prev = previousNode;newNode.next = currentNode;currentNode.prev = newNode;}this.length++;return true;}
// removeAt() 删除指定位置的节点// 重写 removeAt()removeAt(position) {// 1、position 越界判断if (position < 0 || position > this.length - 1) return null;// 2、根据不同情况删除元素let currentNode = this.head;if (position === 0) { // 删除第一个节点的情况if (this.length === 1) { // 链表内只有一个节点的情况this.head = null;this.tail = null;} else { // 链表内有多个节点的情况this.head = this.head.next;this.head.prev = null;}} else if (position === this.length - 1) { // 删除最后一个节点的情况currentNode = this.tail;this.tail.prev.next = null;this.tail = this.tail.prev;} else { // 删除 0 ~ this.length - 1 里面节点的情况let targetIndex = 0;let previousNode = null;while (targetIndex++ < position) {previousNode = currentNode;currentNode = currentNode.next;}previousNode.next = currentNode.next;currentNode.next.perv = previousNode;}this.length--;return currentNode.data;}
// update(position, data) 修改指定位置的节点// 重写 update()update(position, data) {// 1、删除 position 位置的节点const result = this.removeAt(position);// 2、在 position 位置插入元素this.insert(position, data);return result;}
// forwardToString() 链表数据从前往后以字符串形式返回forwardToString() {let currentNode = this.head;let result = '';// 遍历所有的节点,拼接为字符串,直到节点为 nullwhile (currentNode) {result += currentNode.data + '--';currentNode = currentNode.next;}return result;}
// backwardString() 链表数据从后往前以字符串形式返回backwardString() {let currentNode = this.tail;let result = '';// 遍历所有的节点,拼接为字符串,直到节点为 nullwhile (currentNode) {result += currentNode.data + '--';currentNode = currentNode.prev;}return result;}
双向链表的其他方法通过继承单向链表来实现。
class DoublyLinkedList extends LinkedList {constructor() {super();this.tail = null;}// ------------ 链表的常见操作 ------------ //// append(element) 往双向链表尾部追加一个新的元素// 重写 append()append(element) {// 1、创建双向链表节点const newNode = new DoublyNode(element);// 2、追加元素if (this.head === null) {this.head = newNode;this.tail = newNode;} else {// !!跟单向链表不同,不用通过循环找到最后一个节点// 巧妙之处this.tail.next = newNode;newNode.prev = this.tail;this.tail = newNode;}this.length++;}// insert(position, data) 插入元素// 重写 insert()insert(position, element) {// 1、position 越界判断if (position < 0 || position > this.length) return false;// 2、创建新的双向链表节点const newNode = new DoublyNode(element);// 3、判断多种插入情况if (position === 0) {// 在第 0 个位置插入if (this.head === null) {this.head = newNode;this.tail = newNode;} else {//== 巧妙之处:相处腾出 this.head 空间,留个 newNode 来赋值 ==//newNode.next = this.head;this.head.perv = newNode;this.head = newNode;}} else if (position === this.length) {// 在最后一个位置插入this.tail.next = newNode;newNode.prev = this.tail;this.tail = newNode;} else {// 在 0 ~ this.length 位置中间插入let targetIndex = 0;let currentNode = this.head;let previousNode = null;// 找到要插入位置的节点while (targetIndex++ < position) {previousNode = currentNode;currentNode = currentNode.next;}// 交换节点信息previousNode.next = newNode;newNode.prev = previousNode;newNode.next = currentNode;currentNode.prev = newNode;}this.length++;return true;}// getData() 继承单向链表getData(position) {return super.getData(position);}// indexOf() 继承单向链表indexOf(data) {return super.indexOf(data);}// removeAt() 删除指定位置的节点// 重写 removeAt()removeAt(position) {// 1、position 越界判断if (position < 0 || position > this.length - 1) return null;// 2、根据不同情况删除元素let currentNode = this.head;if (position === 0) {// 删除第一个节点的情况if (this.length === 1) {// 链表内只有一个节点的情况this.head = null;this.tail = null;} else {// 链表内有多个节点的情况this.head = this.head.next;this.head.prev = null;}} else if (position === this.length - 1) {// 删除最后一个节点的情况currentNode = this.tail;this.tail.prev.next = null;this.tail = this.tail.prev;} else {// 删除 0 ~ this.length - 1 里面节点的情况let targetIndex = 0;let previousNode = null;while (targetIndex++ < position) {previousNode = currentNode;currentNode = currentNode.next;}previousNode.next = currentNode.next;currentNode.next.perv = previousNode;}this.length--;return currentNode.data;}// update(position, data) 修改指定位置的节点// 重写 update()update(position, data) {// 1、删除 position 位置的节点const result = this.removeAt(position);// 2、在 position 位置插入元素this.insert(position, data);return result;}// remove(data) 删除指定 data 所在的节点(继承单向链表)remove(data) {return super.remove(data);}// isEmpty() 判断链表是否为空isEmpty() {return super.isEmpty();}// size() 获取链表的长度size() {return super.size();}// forwardToString() 链表数据从前往后以字符串形式返回forwardToString() {let currentNode = this.head;let result = "";// 遍历所有的节点,拼接为字符串,直到节点为 nullwhile (currentNode) {result += currentNode.data + "--";currentNode = currentNode.next;}return result;}// backwardString() 链表数据从后往前以字符串形式返回backwardString() {let currentNode = this.tail;let result = "";// 遍历所有的节点,拼接为字符串,直到节点为 nullwhile (currentNode) {result += currentNode.data + "--";currentNode = currentNode.prev;}return result;}}
const doublyLinkedList = new DoublyLinkedList();// append() 测试doublyLinkedList.append("ZZ");doublyLinkedList.append("XX");doublyLinkedList.append("CC");console.log(doublyLinkedList);// insert() 测试doublyLinkedList.insert(0, "00");doublyLinkedList.insert(2, "22");console.log(doublyLinkedList);// getData() 测试console.log(doublyLinkedList.getData(1)); //--> ZZ// indexOf() 测试console.log(doublyLinkedList.indexOf("XX")); //--> 3console.log(doublyLinkedList);// removeAt() 测试doublyLinkedList.removeAt(0);doublyLinkedList.removeAt(1);console.log(doublyLinkedList);// update() 测试doublyLinkedList.update(0, "111111");console.log(doublyLinkedList);// remove() 测试console.log(doublyLinkedList.remove("111111"));console.log(doublyLinkedList.remove("22222"));console.log(doublyLinkedList);// forwardToString() 测试console.log(doublyLinkedList.forwardToString());// backwardString() 测试console.log(doublyLinkedList.backwardString());