javascript实现数据结构 --- 链表

单向链表

/**
 * @function defaultEquals 判断两个值是否相等
 */
export const defaultEquals = (a, b) => {
  return a === b;
}

/**
 * @class Node 添加到链表中的项
 * 
 * element 项的内容
 * next 指针指向下一个项
 */
export class Node {
  constructor(element){
    this._element = element;
    this._next = undefined;
  }
}


/**
 * @class LinkedList 单向链表
 * 
 * push(element):向链表尾部添加一个新元素
 * insert(element, position):向链表的特定位置插入一个新元素。
 * getElementAt(index):返回链表中特定位置的元素。如果链表中不存在这样的元素,则返回 undefined。
 * remove(element):从链表中移除一个元素。
 * indexOf(element):返回元素在链表中的索引。如果链表中没有该元素则返回-1。
 * removeAt(position):从链表的特定位置移除一个元素。
 * isEmpty():如果链表中不包含任何元素,返回 true,如果链表长度大于 0则返回 false。
 * size():返回链表包含的元素个数,与数组的 length 属性类似。
 * toString():返回表示整个链表的字符串。由于列表项使用了 Node 类,就需要重写继承自 JavaScript 对象默认的 toString 方法,让其只输出元素的值。
 * 
 */
export class LinkedList {
  constructor(equalsFn = defaultEquals){
    this._count = 0; // 记录链表长度
    this._head = undefined;  // 记录头部元素
    this._equalsFn = equalsFn; // 用于判断项的内容是否相同
  }

  push(element){
    const node = new Node(element);
    let current;

    if(this._head == null){
      this._head = node;
    } else {
      current = this._head;
      // 寻找最后一个元素
      while(current._next !=  null){
        current = current._next;
      }
      current._next = node;
    }

    this._count++;
  }

  getElementAt(index){
    if(index >= 0 && index < this._count){
      let current = this._head;
      for (let i = 0; i < index && current != null; i++) {
        current = current._next; 
      }
      return current;
    }

    return undefined
  }

  removeAt(index){
    if(index >= 0 && index < this._count){
      let current = this._head;

      if(index == 0){
        this._head = current._next;
      } else {
        const previous = this.getElementAt(index -1);
        current = previous._next;
        // 将 previous 与 current 的下一项链接起来:跳过 current,从而移除它
        previous._next = current._next;
      }

      this._count--;
      return current._element;
    }

    return undefined;
  }

  insert(element, index){
    if(index >= 0 && index < this._count){
      const node = new Node(element);

      if(index == 0){
        const current = this._head;
        node._next = current;
        this._head = node;
      }else {
        const previous = this.getElementAt(index -1);
        const current = previous._next;
        node._next = current;
        previous._next = node;
      }

      this._count ++;
      return true;
    }

    return false;
  }

  indexOf(element){
    let current = this._head;
    for(let i = 0; i < this._count && current != null; i++){
      if(this._equalsFn(element, current._element)){
        return i;
      }
      current = current._next;
    }

    return -1;
  }

  remove(element) { 
    const index = this.indexOf(element); 
    return this.removeAt(index); 
  }

  size() { 
    return this._count; 
  }

  isEmpty() { 
    return this.count === 0; 
  }

  getHead() { 
    return this._head; 
  }

  toString() { 
    if (this._head == null) {
      return ''; 
    } 

    let objString = `${this._head._element}`;
    let current = this._head._next;

    for (let i = 1; i < this.size() && current != null; i++) {
      objString = `${objString},${current._element}`; 
      current = current._next; 
    } 

    return objString;
  }
}

// 测试
const list = new LinkedList(); 
console.log(list.isEmpty());
list.push(15); 
list.push(10);
list.push(14); 
list.push(11);
console.log(list.indexOf(14));
list.removeAt(list.indexOf(14))
list.remove(11);
list.insert(55,0);
list.insert(56,1);
console.log(list.size());
console.log(list.getHead());
console.log(list.isEmpty());
console.log(list.toString());

双向链表

import { defaultEquals, Node, LinkedList } from './LinkedList.js'

/**
 * @class DoublyNode
 * @extends {Node}
 * 
 * prev 指针指向上一个项
 */
class DoublyNode extends Node {
  constructor(element, next, prev){
    super(element, next);
    this._prev = prev;
  }
}

/**
 * @class DoublyLinkedList 双向链表
 * @extends {LinkedList}
 * 
 * insert(element, position):向链表的特定位置插入一个新元素。
 * removeAt(position):从链表的特定位置移除一个元素。
 * 
 */
class DoublyLinkedList extends LinkedList {
  constructor(equalsFn = defaultEquals) { 
    super(equalsFn);
    this._tail = undefined; // 记录尾部元素
  }

  insert(element, index){
    if (index >= 0 && index <= this._count) {
      const node = new DoublyNode(element);
      let current = this._head;
      if(index === 0){
        if (this._head == null) {
          this._head = node; 
          this._tail = node; 
        } else { 
          node.next = this._head;
          current._prev = node;
          this._head = node;
        }
      }else if(index === this._count){
        current = this._tail;
        current._next = node;
        node._prev = current;
        node._next = node;
      }else {
        const previous = this.getElementAt(index - 1);
        current = previous._next;
        node._next = current;
        previous._next = node;
        current._prev = node;
        node._prev = previous;
      }

      this._count++;
      return true;
    }

    return false;
  }

  removeAt(index){
    if (index >= 0 && index < this._count) {
      let current = this._head;
      if(index === 0){
        this._head = current._next;
        if (this.count === 1) {
          this._tail = undefined; 
        } else { 
          this._head._prev = undefined;
        }
      }else if(index === this._count - 1){
        current = this._tail;
        this._tail = current._prev;
        this._tail._next = undefined;
      }else {
        current = this.getElementAt(index);
        const previous = current._prev;
        previous._next = current._next;
        current._next._prev = previous;
      }

      this._count--;
      return current._element;
    }

    return undefined;
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值