LinkedList


function defaultEquals(a, b) {
    return a === b
}

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

class LinkedList {
    constructor (equalsFn = defaultEquals) {
        this.count = 0
        this.head = null
        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++
    }
    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
    }
    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
        } else {
            return undefined
        }
    }
    remove (element) {
        const index = this.indexOf(element)
        return this.removeAt(index)
    }
    removeAt (index) {
        if (index >= 0 && index <= this.count) {
            let current = this.head
            if (index === 0) {
                this.head = current.next
            } else {
                let previous
                for (let i = 0; i < index; i++) {
                    previous = current
                    current = current.next
                }
                previous.next = current.next
            }
            this.count--
            return current.element
        }
        return undefined
    }
    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
    }
    isEmpty () {
        return this.size() === 0
    }
    size () {
        return this.count
    }
    getHead () {
        return this.head
    }
    toString () {
        if (this.head == null) {
            return ''
        }
        let objString = `${this.head.element}`
        let current = this.head.next
        for (let i = 0; i < this.size() && current != null; i++) {
            objString = `${objString}, ${current.element}`
            current = current.next

        }
        return objString
    }
}

双向链表: DoublyLinkedList

function defaultEquals(a, b) {
    return a === b
}

class Node {
    constructor (element) {
        this.element = element
        this.next = null
        this.prev = null
    }
}
class DoublyLinkedList {
    constructor (equalsFn = defaultEquals) {
        this.count = 0
        this.head = null
        this.tail = null
        this.equalsFn = equalsFn
    }

    push (element) {
        const node = new Node(element)
        let current
        if (this.head == null) {
            this.head = node
            this.tail = node
        } else {
            current = this.head
            while (current.next != null) {
                // 遍历到最后一项
                current = current.next
            }
            current.next = node
            this.tail = node
            node.prev = current
        }
        this.count++
    }
    insert (element, index) {
        if (index >= 0 && index <= this.count) {
            const node = new Node(element)
            if (index === 0) {
                if (this.head == null) {
                    this.head = node
                    this.tail = node
                } else {
                    node.next = this.head
                    this.head = node
                    current.prev = node
                }
            } else if (index === this.count) {
                current = this.tail
                current.next = node
                this.tail = node
                node.prev = current
            } else {
                const previous = this.getElementAt(index-1)
                const current = previous.next
                node.next = current
                previous.next = node
                current.prev = node
                node.prev = previous
            }
            this.count++
            return true
        }
        return false
    }
    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
        } else {
            return undefined
        }
    }
    remove (element) {
        const index = this.indexOf(element)
        return this.removeAt(index)
    }
    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 = null
                } else {
                  this.head.prev = null
                }
            } else if (index === this.count - 1) {
                current = this.tail
                this.tail = current.prev
                this.tail.next = null
            } else {
                current = this.getElementAt(index)
                const previous = current.prev
                previous.next = current.next
                current.next.prev = previous
            }
            this.count--
            return current.element
        }
        return undefined
    }
    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
    }
    isEmpty () {
        return this.size() === 0
    }
    size () {
        return this.count
    }
    getHead () {
        return this.head
    }
    toString () {
        if (this.head == null) {
            return ''
        }
        let objString = `${this.head.element}`
        let current = this.head.next
        for (let i = 0; i < this.size() && current != null; i++) {
            objString = `${objString}, ${current.element}`
            current = current.next

        }
        return objString
    }
}

StackLinkedList

class StackLinkedList extends DoublyLinkedList {
  constructor () {
    this.items = new DoublyLinkedList()
  }
  push (element) {
    this.items.push(element)
  }
  pop () {
    if (this.isEmpty()) {
      return undefined
    }
    return this.items.removeAt(this.size() - 1)
  }
  peek () {
    if (this.isEmpty) {
      return undefined
    }
    return this.items.getElementAt(this.size()-1).element
  }
  isEmpty () {
    return this.items.isEmpty()
  }
  size () {
    return this.items.size()
  }
  clear () {
    this.items.clear()
  }
  toString () {
    return this.items.toString()
  }
}

循环链表: CircularLinkedList

class CircularLinkedList extends LinkedList {
  constructor(equalsFn = defaultEquals) {
    super(equalsFn)
  }
  push (element) {
    const node = new Node(element)
    let current
    if (this.head == null) {
        this.head = node
    } else {
        current = this.getElementAt(this.size() - 1)
        current.next = node
    }
    node.next = this.head
    this.count++
  }
  insert (element, index) {
    if (index >= 0 && index <= this.count) {
      const node = new Node(element)
      let current = this.head
      if (index === 0) {
        if (this.head == null) {
          this.head = node
          node.next = this.head
        } else {
          node.next = current
          current = this.getElementAt(this.size())
          this.head = node
          current.next = this.head
        }
      } else {
        const previous = this.getElementAt(index-1)
        node.next = previous.next
        previous.next = node
      }
      this.count++
      return true
    }
    return false
  }

  removeAt (index) {
      if (index >= 0 && index <= this.count) {
          let current = this.head
          if (index === 0) {
              if (this.size() === 0) {
                  this.head = null
              } else {
                  const removed = this.head
                  current = this.getElementAt(this.size())
                  this.head = this.head.next
                  current.next = this.head
                  current = removed
              }
          } else {
              const previous = this.getElementAt(index-1)
              current = previous.next
              previous.next = current.next
          }
          this.count--
          return current.element
      }
      return undefined
  }
}