Common Data Structures in JavaScript

When it comes to data structures, the majority of textbooks typically demonstrate implementation using languages such as C or Java. However, with the increasing popularity of Jamstack, it is crucial to carefully evaluate and select efficient data structures for client-side state management as well, considering both their advantages and limitations.

coding cat that is ready to dive

I will be referencing examples from the public repository trekhleb/javascript-algorithms in my blog post, but presenting them in a different manner. I encourage readers to adapt the underlying implementations to suit their specific needs.

Linked List

Linked List

A linked list is a linear combination of data elements, where each element points to the next. This is particular useful to apply insert or delete on any particular node. For example,

class ListNode {
  val: number
  next: ListNode | null
  constructor(val?: number, next?: ListNode | null) {
    this.val = val === undefined ? 0 : val
    this.next = next === undefined ? null : next
  }
}

Say we want to insert a new node or delete a node, it would be quite easy to unlink the existed node and attach or skip it.

Doubly-linked List

This is an extension of linked list with an extra property prev, which makes it faster to go through each node from reversed direction.

class AnotherListNode {
  val: number
  next: ListNode | null
  prev: ListNode | null

  constructor(val?: number, next?: ListNode | null, prev?: ListNode | null) {
    this.val = val === undefined ? 0 : val
    this.next = next === undefined ? null : next
    this.prev = prev === undefined ? null : prev
  }
}

Hash Table

Hash Table

A hash table is a structure that maps keys to values with a hash function that compute an index for lookup. There will be cases when hash functions maps different keys to the same index, in this case we will create a chain for iteration (can be a linked list).

Hash Table: Collision Resolution

In JavaScript, we could use object or Map to represent usage of hash tables.

Stack

Stack

A stack represents a collection of items with two operations, push & pop that follow first-in-last-out (LIFO) principles so that this collection maintains the order. We will explain more in another article.

Queue

Queue

A queue represents a collection of items with two operations, enqueue & dequeue that follow first-in-first-out (FIFO) principles so that this collection maintains the order. We will explain more in another article.

Priority Queue

A priority queue is a queue such that an element with high priority is served before an element with low priority. In this case, the order is determined by another comparator instead.

Tree

Tree

A tree is a collection of nodes starting at a root node, where each node is a data structure consisting of a value, together with a list of references to children nodes, with the constraints that no reference is duplicated, and none points to the root. For example, a binary tree can be defined like the following:

class TreeNode {
  val: number
  left: TreeNode | null
  right: TreeNode | null
  constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
    this.val = val === undefined ? 0 : val
    this.left = left === undefined ? null : left
    this.right = right === undefined ? null : right
  }
}

Graph

Graph

A graph a collection of vertices or nodes together with a set of pair of these vertices called edges. If such edges are in a particular order, it's a directed graph otherwise undirected.

This is the most generic concepts of data structure used in mathematics, especially in the branch Graph Theory. For example,

  • An array is a undirected graph where each edge works as index of the element.
  • A linked list is a directed graph where each edge starts from a non-repeated vertex to another non-repeated vertex.
  • A tree is a directed graph where the graph starts from root node and points outward.

Final notes

I guess it would be rather easier with more examples, let's continue in future posts...