Search code examples
javascriptdata-structureslinked-list

I'm coding a linked list in JS and a prepend function that I wrote is not working how I intended


So my initial code looks like this:

class LinkedList {
  constructor() {
    this.head = new Node(-1);
    this.tail = this.head;
  };
  prepend(value) {
    let next = this.head.nextNode;
    this.head = new Node(value);
    this.head.nextNode = next;
  };
};

class Node {
  constructor(value, nextNode = null) {
    this.value = value;
    this.nextNode = nextNode;
  };
};

Let's say I were to prepend a value of 1, and then prepend another value of 2. The output would look something like this:

LinkedList = {
  head: {
    nextNode: null,
    value: 2
  },
  tail: {
    nextNode: null,
    value: -1
  }
};

This isn't really what I intended. I instead want the head's value to equal 2, and then for the head to point to a new node with a value of 1.

I'm quite lost on how to fix this, and I didn't want to just look up the answer since I'm trying to learn how to implement something like this on my own after learning the concept for the first time. I'd be grateful for any help I can get. I would prefer if you could give me a hint to nudge me in the right direction, and then put the correct way to fix this below that, as I'm still set on figuring this out without looking up the answer. Thanks in advance!


Solution

  • If you use some fake node for an empty list you should clear it before adding real nodes.

    For the next node you should take this.head instead of this.head.nextNode (initially null).

    Also you don't use Node's constructor's second parameter - pass the next node directly to the constructor:

    class LinkedList {
      constructor() {
        this.tail = this.head = new Node(-1);
      };
      prepend(value) {
        if(this.head.value === -1 && this.head.nextNode === null){ // an empty list, delete the head and tail
          delete this.head, delete this.tail;
        }
        this.head = new Node(value, this.head); // leverage the Node's constructor to pass the next node
        this.tail ??= this.head; // set the tail on the first node
      };
    };
    
    class Node {
      constructor(value, nextNode = null) {
        this.value = value;
        this.nextNode = nextNode;
      };
    };
    
    const list = new LinkedList;
    
    list.prepend(1);
    list.prepend(2);
    
    console.log(JSON.stringify(list, null, 4));
    .as-console-wrapper { top: 0; max-height: 100% !important; }

    I suggest to change -1 to a symbol:

    class LinkedList {
      static EMPTY_NODE = Symbol();
      constructor() {
        this.tail = this.head = new Node(LinkedList.EMPTY_NODE);
      };
      prepend(value) {
        if(this.head.value === LinkedList.EMPTY_NODE){
          delete this.head, delete this.tail;
        }
        this.head = new Node(value, this.head);
        this.tail ??= this.head;
      };
    };
    
    class Node {
      constructor(value, nextNode = null) {
        this.value = value;
        this.nextNode = nextNode;
      };
    };
    
    const list = new LinkedList;
    
    list.prepend(1);
    list.prepend(2);
    
    console.log(JSON.stringify(list, null, 4));
    .as-console-wrapper { top: 0; max-height: 100% !important; }

    But for an empty list I would prefer the head and tail being null:

    class LinkedList {
      constructor() {
        this.tail = this.head = null;
      };
      prepend(value) {
        this.head = new Node(value, this.head);
        this.tail ??= this.head;
      };
    };
    
    class Node {
      constructor(value, nextNode = null) {
        this.value = value;
        this.nextNode = nextNode;
      };
    };
    
    const list = new LinkedList;
    
    list.prepend(1);
    list.prepend(2);
    
    console.log(JSON.stringify(list, null, 4));
    .as-console-wrapper { top: 0; max-height: 100% !important; }