An Implementation of Double Linked Lists

Lawson Hung
4 min readApr 4, 2020

Next on the list of data structures to implement is the Double Linked List.

I found this tutorial to code along to.

https://dev.to/miku86/javascript-data-structures-doubly-linked-list-intro-and-setup-275b

I’m able to create new nodes, push those nodes into a Double Linked List, pop, unshift and shift. This is my Node.js class in Javascript.

export class Node{// Syntax: new Node(value);constructor(value){// this refers to the current instance of Node// Used like: node1.value, node1.prev, node1.nextthis.value = value;// Initialize this.prev and this.next as nullthis.prev = null;this.next = null;}}

Since I wanted to practice ES6 import syntax, I had to make some modifications. First, in order to import modules, node looks for the closest parent package.json file. To make things easy, since I couldn’t find the closest package.json file, I just created a new file called package.json and saved it in my working directory/repo. In my package.json, I just have the following code.

{"type": "module"}

When I run node, this just tells npm to look for modules. Now I can import modules with ES6 syntax. At the top of my DoublyLinkedList.js file, I have this code.

import { Node } from './Node.js';

And when I run it in the terminal to test it, I have to do it like so.

$ node --experimental-modules DoublyLinkedList.js

Now I’m able to test my DoublyLinkedList. This is my code for DoublyLinkedList.js.

// A Doubly Linked List has a length, a beginning (= head), an end (= tail)class DoublyLinkedList{constructor(){this.length = 0;this.head = null;this.tail = null;}/*** Add node to end* Return newly added node* @return {Node}*/push(value){// Create a new nodeconst newNode = new Node(value);// If the list is empty, the new node should become the head and tailif(!this.length){this.head = newNode;this.tail = newNode;} else {// The current tail should point forward (= next) to the new nodethis.tail.next = newNode;// The new node should point back (= prev) to the current tailnewNode.prev = this.tail;// The new node should become the new tailthis.tail = newNode;}// Increment length by 1this.length++;// Return new nodereturn newNode;}/*** Remove node from end* Return removed node* @return {Node}*/pop(){// No node in the list so it's empty, therefore return null// this.length = false if empty, so !this.length returns trueif(!this.length){return null;} else {// Save current tail to return to laterconst nodeToRemove = this.tail;if(this.length === 1){// After removing the only node, there will be no head and tailthis.head = null;this.tail = null;} else {// Set the node before the current tail as the new tailthis.tail = this.tail.prev;// Remove the connection from the new tail to the old tail, after reassigning the new tailthis.tail.next = null;// Remove the connection from the old tail to the next tailnodeToRemove.prev = null;}// Decrement length by 1this.length--;// Return old tailreturn nodeToRemove;}}/*** Add node to beginning* Return newly added Node* @returns {Node}*/unshift(value){// Create a new nodeconst newNode = new Node(value);// If list is empty, set head and tail to new node// this.length = 0 = false when empty, so !this.length would return true when emptyif (!this.length) {this.head = newNode;this.tail = newNode;} else {// Set new node's next to current headnewNode.next = this.head;// Set the current head's prev to new nodethis.head.prev = newNode;// Set list's head to new nodethis.head = newNode;}// Increment length by 1this.length++;// return new nodereturn newNode;}/*** Remove Node from beginning* Return removed node* @return {Node}*/shift(){// If the list is empty, return null. We can't remove data from an empty list// this.length = 0 = false if empty, so !this.length returns trueif (!this.length) {return null;}// Set head as nodeToRemoveconst nodeToRemove = this.head;// After removing the only element, the list will be empty, so head and tail will be nullif (this.length === 1) {this.head = null;this.tail = null;} else {// The node after nodeToRemove becomes the new headthis.head = nodeToRemove.next;// Remove both connections from the new head and the old head (nodeToRemove)this.head.prev = null;nodeToRemove.next = null;}// Decrement length by 1this.length--;// Return nodeToRemovereturn nodeToRemove;}}

These functions work just like you would expect them to work, pop, push, unshift and shift. It definitely helped to recode everything from scratch. I understand what’s happening under the hood a lot better.

Happy quarantining! #Covid-19 #Coronavirus

--

--