In this series of articles I would like to show why the classic data structures are useful for JS developers. For this case I will use a typical Hash Table with Linked Lists.

Find all documentation and code about this article in the Github repo.

A Hash Table is a simple array with an static size. Each array contains a linked list. The list contains not-repeated elements.

In a Hash Table each time you make an action with an item (insert, erase or find) he is passed through the Hash Function that returns the index of the bucket where the item should be placed. This means that you are saving a lot of iterations because you know in which bucket will perform your actions for each input.

Hash Function Example

To explain how the lists works I prefer to start with the nodes that compose them.

class LListNode { constructor(value, next) { this.value = value; this.next = next; } // getters and setters…. }

Very simple, right? A Linked List Node are just composed by its value and the next element.

A Linked List is a chain of nodes, starting from a header node. (I am not showing all the methods but you can check them in the Github repo)

class LList { constructor(values) { let current; this.header = new LListNode(null, null); current = this.header; for (const value of values) { let newNode = new LListNode(value, null); current.setNext(newNode); current = newNode; } }

// Cost: O(1) begin() { return LListIterator[Symbol.iterator](this.header.getNext(), this); }

// Cost: O(n) clone(node) { if (node === null) return null; else return new LListNode(node.getValue(), this.clone(node.getNext())); } // Cost: O(1) insert(pos, val) { const newNode = new LListNode(val, pos.current().getNext()); pos.current().setNext(newNode); pos.next(); return pos; }

}

The list has just the header element as the class data. Every method iterates from that node.

The insert method needs a position where insert the new node. The node in the position now points to the new node while this points to the next of the position passed as parameter. The erase method works pretty similar but has a cost of O(n) instead O(1) because it needs to access the previous node that in this type of List has a cost of O(n).

The clone method gets advantage from the architecture of this data structure to use a simple recursion algorithm an link every node to form the new list.

Begin returns an iterator pointing to the first item (next of header).

Linked List Data Structure

The List iterator should go visiting the next node of each one until reach null.

const LListIterator = { [Symbol.iterator]: (node, llist) => { let current = node; if (node === null) current = llist.header; return { next: () => { if (current === null || current.getNext() === null) { return { done: true }; } current = current.getNext(); return { value: current, done: false }; } }; } };

Check now how the Hash Table works. It has 3 elements as data:

Elements: Counts the number of total elements in the table

Size: Static number of buckets in the table

Buckets: Array that contains Linked Lists

class HashTable { constructor(size) { this.elements = 0; this.size = size; this.buckets = []; for (let i = 0; i < size; i++) { this.buckets.push(new LList([])); } }

find(item) { let pos = this.hashFunction(item); return this.buckets[pos].find(item); }

erase(item) { const pos = this.hashFunction(item); const list = this.buckets[pos]; const itemToErase = list.find(item); if (itemToErase !== list.end()) { list.erase(itemToErase); this.elements--; } } }

Hash Table Data Structure

By other side the Hash Table iterator, goes deeply in every bucket. That means that if you are in the bucket 0 it will act as a Linked List Iterator until reach the last item of the Bucket 0 list, then it will get next and iterate through bucket 1 list.

The code of this part is available in the Github repo

What is the real value of using this data structure?

Firstly, there is a premise about using Hash Tables previously noted. It stores non-repeated values. There’s a lot of real cases where you havent repeated values. For example: retreiving data from a relational database that has unique ids. You can store whatever you want in a node, so you could easily create a function to find for an attribute

const hTable = new HashTable(10);

hTable.insert({

id: 1,

value: "Cat"

});

hTable.insert({

id: 56,

value: "Dog"

});

const value = hTable.findById(56); // This function is not implemented in the repo

Real Example:

In a typical array if you have 1000 elements and you need to find one specific item you have to iterate through all of them. Thats a O(n) cost, so O(1000).

Supose that we create a Hash Table of 100 buckets with a total of 1000 elements like the previous array. You will have (by average) 10 elements by list and by bucket. The cost of the Hash Function is O(1) and as you can look, the cost of find that element in the Hash Table is vastly better than in the array (~100x aprox) because you have to iterate around an average of 10 elements instead 10.

React Hash Table App

To check the behavior of this data structure, I created a simple React App to show live changes. Feel free to fork the repo and make your improvements.

This is the link to the app deployed in heroku:

Find all documentation and code about this article in the Github repo.

Reach me on twitter (@Oliver_ap)