Skip to content

Popular data structures implemented in Javascript: stack, queue, set, priority queue, binary search tree, graph, linked list, heap, trie

Notifications You must be signed in to change notification settings

sonttran/data-structure

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Popular data structures implemented in Javascript

Content

Stack

Stack

 var myStack = new Stack(); console.log(myStack.length()); // 0 console.log(myStack.push('a')); // undefined (push return no value) console.log(myStack.push('b')); // undefined console.log(myStack.push('c')); // undefined console.log(myStack.pop()); // c console.log(myStack.top()); // b console.log(myStack.bottom()); // a console.log(myStack.length()); // 2 const Stack = function() { let count = 0; let content = {}; this.push = function(value) { // add value on top of the stack content[count] = value; count++; }; this.pop = function() { // remove value at top of the stack and return that value if(count === 0) { return undefined } count--; var popped = content[count]; delete content[count]; return popped; }; this.length = function() { return count } // return number of values in stack this.top = function() { // return the value on top of the stack if(count === 0 ) { return undefined } return content[count-1] } this.bottom = function() { // return the value at the bottom of the stack if(count === 0 ) { return undefined } return content['0'] } }
  • Javascript array object has all Stack data structure attributes and methods. However, we can always implement a stack data structure by ourself and add more property/method as we want.

Set

Set

 const mySet = new Set(); console.log(mySet.add('a')); // a is added to set! console.log(mySet.exist('a')); // true console.log(mySet.exist('b')); // false console.log(mySet.list()); // [ 'a' ] console.log(mySet.add('b')); // b is added to set! console.log(mySet.add('c')); // c is added to set! console.log(mySet.remove('c')); // c is removed from set! console.log(mySet.list()); // [ 'a', 'b' ] console.log(mySet.length()); // 2 const mySet2 = new Set(); console.log(mySet2.add('a')); // a is added to set! console.log(mySet2.add('g')); // g is added to set! console.log(mySet2.add('h')); // h is added to set! console.log(mySet2.list()); // [ 'a', 'g', 'h' ] console.log(mySet.union(mySet2).list()); // [ 'a', 'b', 'g', 'h' ] console.log(mySet.intersect(mySet2).list()); // [ 'a' ] console.log(mySet.difference(mySet2).list()); // [ 'b', 'g', 'h' ] const Set = function() { let set = []; this.exist = function(element) { // check if element is in set return true, else return false return (set.indexOf(element) !== -1) } this.add = function(element) { // add element to set if not exist, do not add if it exists if(!this.exist(element)) { set.push(element); return `${element} is added to set!`; } } this.list = function() { // list all element in set return set; } this.remove = function(element) { // remove an element if it's in set if(this.exist(element)) { set.splice(set.indexOf(element), 1); return `${element} is removed from set!`; } else { return `${element} is not in set!`; } } this.length = function() { // return number of element in set return set.length; } this.union = function(setC) { // return the union set of two sets let union = new Set(); let setA = this.list(); let setB = setC.list(); for(let i = 0; i < setA.length; i++) { union.add(setA[i]); } for(let j = 0; j < setB.length; j++) { union.add(setB[j]); } return union; } this.intersect = function(setC) { // return a set of intersection of 2 sets let intersect = new Set(); let setA = this; let setB = setC.list(); for(let i = 0; i < setB.length; i++) { if(setA.exist(setB[i])) { intersect.add(setB[i]) } } return intersect; } this.difference = function(setC) { // return a set of difference of 2 sets let setA = this; let difference = setA.union(setC); let setB = setA.intersect(setC).list(); for(let i = 0; i < setB.length; i++) { difference.remove(setB[i]); } return difference; } }

Queue

Queue

 const myQueue = new Queue(); myQueue.enqueue('a'); myQueue.enqueue('b'); myQueue.enqueue('c'); myQueue.list(); // [ 'a', 'b', 'c' ] console.log(myQueue.dequeue()); // a console.log(myQueue.front()); // b console.log(myQueue.length()); // 2 console.log(myQueue.isEmpty()); // false myQueue.list(); // [ 'b', 'c' ] function Queue() { // first in, first out (FIFO) const content = []; this.list = function() { console.log(content) }; // list all queue item this.enqueue = function(element) { content.push(element) }; // put item to the queue this.dequeue = function() { return content.shift() }; // get the first item in the queue, remove it from the queue this.front = function() { return content[0] }; // get the first item in the queue, still let it be in the queue this.length = function() { return content.length }; // get queue length this.isEmpty = function() { return (content.length == 0) } // check if queue is empty }

Priority Queue

Priority Queue

 const myQueue = new priorityQueue(); myQueue.enqueue(['a', 2]); myQueue.enqueue(['b', 3]); myQueue.list(); // [ [ 'a', 2 ], [ 'b', 3 ] ] myQueue.enqueue(['c', 4]); myQueue.list(); // [ [ 'a', 2 ], [ 'b', 3 ], [ 'c', 4 ] ]  myQueue.enqueue(['d', 3]); myQueue.list(); // [ [ 'a', 2 ], [ 'b', 3 ], [ 'd', 3 ], [ 'c', 4 ] ]  myQueue.enqueue(['e', 1]); myQueue.list(); // [ [ 'e', 1 ], [ 'a', 2 ], [ 'b', 3 ], [ 'd', 3 ], [ 'c', 4 ] ]  console.log(myQueue.dequeue()); // [ 'e', 1 ] console.log(myQueue.front()); // [ 'a', 2 ] console.log(myQueue.length()); // 4 console.log(myQueue.isEmpty()); // false function priorityQueue() { // Queue where item with highest priority get out first no matter when added const content = []; this.list = function() { console.log(content) }; // list all queue item this.dequeue = function() { return content.shift() }; // get the first item in the queue, remove it from the queue this.front = function() { return content[0] }; // get the first item in the queue, still let it be in the queue this.length = function() { return content.length }; // get queue length this.isEmpty = function() { return (content.length == 0) } // check if queue is empty this.enqueue = function(element) { // put item to the queue with priority if(this.isEmpty()) { return content.push(element) }; var added = false; for(let i = 0; i < content.length; i ++) { // 1 is highest priority if(element[1] < content[i][1]) { content.splice(i, 0, element); added = true; break; } } if(!added) { content.push(element) } }; }

Binary search tree

Binary search tree

  • Search item in tree fast O(log n), find min and max, inOrder, preOrder, postOrder, levelOrder
  • preOrder used when need to explore the roots before inspecting any leaves
  • postOrder used when need to explore all the leaves before any nodes
  • inOrder used when need to flatten the tree back into its sequence (bottom up)
  • levelOrder used when need to inspect nodes at height level
 const util = require('util') class Node { constructor(data, left = null, right = null) { this.data = data; this.left = left; this.right = right; } } class binarySearchTree { constructor() { this.root = null } add(data) { // add node to binary tree const node = this.root; if(this.root === null) { this.root = new Node(data) } else { searchLeaf(node); function searchLeaf(node) { if(data < node.data) { if(node.left === null) { return node.left = new Node(data) } searchLeaf(node.left); } else if(data > node.data) { if(node.right === null) { node.right = new Node(data) } searchLeaf(node.right); } else { return null } } } } findMin() { // find min value in binary tree let current = this.root; while(current.left !== null) { current = current.left } return current.data; } findMax() { // find max value in binary tree let current = this.root; while(current.right !== null) { current = current.right } return current.data; } exist(data) { // check if a data is in binary tree let current = this.root; while(current) { if(current.data === data) { return true } else if(current.data > data) { current = current.left } else { current = current.right } } return false } remove(data) { // remove a node from binary tree this.root = removeNode(this.root, data); function removeNode(node, data) { if(node == null) { return null } // root node/tree has nothing in it if(data < node.data) { // not match, move to left node.left = removeNode(node.left, data); } else if(data > node.data) { // not match, move to right node.right = removeNode(node.right, data); } else { // found matching node if(node.left === null && node.right === null) { return null } // no children if(node.left === null) { return node.right } // has right child if(node.right === null) { return node.left } // has left child let rightThenFarthestLeft = node.right; // has both left, right child while(rightThenFarthestLeft.left !== null) { rightThenFarthestLeft = rightThenFarthestLeft.left; } node.data = rightThenFarthestLeft.data; removeNode(node.right, rightThenFarthestLeft.data); } return node; } } findMinHeight(node = this.root) { // get min height of tree if (node == null) { return -1 } let left = this.findMinHeight(node.left); let right = this.findMinHeight(node.right); if (left < right) { return left + 1 } else { return right + 1 } } findMaxHeight(node = this.root) { // get max height of tree if (node == null) { return -1 } let left = this.findMaxHeight(node.left); let right = this.findMaxHeight(node.right); if (left < right) { return right + 1 } else { return left + 1 } } isBalanced() { // check if tree is balanced return (this.findMinHeight() >= this.findMaxHeight() - 1) } inOrder() { // traverse tree to array min -> max if (this.root == null) { return null } else { var result = new Array(); traverseInOrder(this.root); return result; function traverseInOrder(node) { node.left && traverseInOrder(node.left); result.push(node.data); node.right && traverseInOrder(node.right); } }; } bottomUp() { return this.inOrder() } // synonym of inOrder  topDown() { // traverse tree to array max -> min if (this.root == null) { return null; } else { var result = new Array(); traverseInOrder(this.root); return result; function traverseInOrder(node) { node.right && traverseInOrder(node.right); result.push(node.data); node.left && traverseInOrder(node.left); } }; } preOrder() { if (this.root == null) { return null } else { var result = new Array(); function traversePreOrder(node) { result.push(node.data); node.left && traversePreOrder(node.left); node.right && traversePreOrder(node.right); }; traversePreOrder(this.root); return result; }; } postOrder() { if (this.root == null) { return null } else { var result = new Array(); function traversePostOrder(node) { node.left && traversePostOrder(node.left); node.right && traversePostOrder(node.right); result.push(node.data); }; traversePostOrder(this.root); return result; } } levelOrder() { let result = []; let Q = []; if (this.root != null) { Q.push(this.root); while(Q.length > 0) { let node = Q.shift(); result.push(node.data); if (node.left != null) { Q.push(node.left); }; if (node.right != null) { Q.push(node.right); }; }; return result; } else { return null; }; }; } var myBt = new binarySearchTree(); myBt.add(4); myBt.add(1); myBt.add(8); myBt.add(0.5); myBt.add(2); myBt.add(1.6); myBt.add(2.2); myBt.add(1.4); myBt.add(1.7); console.log(util.inspect(myBt, {showHidden: false, depth: null})); // { // root : { // data : 4, // left : { // data : 1, // left : {  // data: 0.5,  // left: null,  // right: null  // }, // right : { // data : 2, // left : { // data : 1.6, // left : {  // data : 1.4,  // left : null,  // right : null  // }, // right : {  // data : 1.7,  // left : null,  // right : null  // }  // }, // right: {  // data: 2.2,  // left: null,  // right: null  // }  // }  // }, // right : {  // data: 8,  // left: null,  // right: null  // }  // }  // } console.log(myBt.findMin()); // 0.5 console.log(myBt.findMax()); // 8 console.log(myBt.exist(5)); // false console.log(myBt.exist(2.2)); // true console.log(myBt.findMinHeight()); // 1 console.log(myBt.findMaxHeight()); // 4  console.log(myBt.inOrder()); // [ 0.5, 1, 1.4, 1.6, 1.7, 2, 2.2, 4, 8 ] console.log(myBt.bottomUp()); // [ 0.5, 1, 1.4, 1.6, 1.7, 2, 2.2, 4, 8 ]  console.log(myBt.isBalanced()); // false console.log(myBt.topDown()); // [ 8, 4, 2.2, 2, 1.7, 1.6, 1.4, 1, 0.5 ] console.log(myBt.preOrder()); // [ 4, 1, 0.5, 2, 1.6, 1.4, 1.7, 2.2, 8 ] console.log(myBt.postOrder()); // [ 0.5, 1.4, 1.7, 1.6, 2.2, 2, 1, 8, 4 ] console.log(myBt.levelOrder()); // [ 4, 1, 8, 0.5, 2, 1.6, 2.2, 1.4, 1.7 ] console.log(myBt.remove(1)); console.log(util.inspect(myBt, {showHidden: false, depth: null})); // { // root : { // data : 4, // left : { // data : 1.4, // left : {  // data : 0.5,  // left : null,  // right : null  // }, // right : {  // data : 2,  // left : { // data : 1.6, // left : null, // right : {  // data : 1.7,  // left : null,  // right : null  // } // }, // right : {  // data : 2.2,  // left : null,  // right : null  // }  // }  // }, // right : {  // data : 8,  // left : null,  // right : null  // }  // }  // }

Hash tables

Hash table

  • The average time for each look up is not tied to the number of elements stored in the table
  • Time complexity for search, insert and delete is O(1)
  • But time to add an element is longer, vary to table size
 var hash = (string, max) => { // return hash number  var hash = 0; for (var i = 0; i < string.length; i++) { hash += string.charCodeAt(i); } return hash % max; // simple hash function return value from 0 to max }; let HashTable = function() { let storage = []; const storageLimit = 4; // define hash table size this.print = function() { console.log(storage) } this.add = function(key, value) { // add [key, value] to hash table var index = hash(key, storageLimit); if (storage[index] === undefined) { storage[index] = [ [key, value] ]; } else { var inserted = false; for (var i = 0; i < storage[index].length; i++) { // collision will be stored in same hash position if (storage[index][i][0] === key) { storage[index][i][1] = value; inserted = true; } } if (inserted === false) { storage[index].push([key, value]); } } }; this.remove = function(key) { // remove [key, value] from hash table var index = hash(key, storageLimit); if (storage[index].length === 1 && storage[index][0][0] === key) { delete storage[index]; } else { for (var i = 0; i < storage[index].length; i++) { // check if there is collision if (storage[index][i][0] === key) { delete storage[index][i]; } } } }; this.lookup = function(key) { // lookup and return [key, value] in hash table var index = hash(key, storageLimit); if (storage[index] === undefined) { return undefined; } else { for (var i = 0; i < storage[index].length; i++) { // check if there is collision if (storage[index][i][0] === key) { return storage[index][i][1]; } } } }; }; console.log(hash('quincy', 10)) // 5 let ht = new HashTable(); ht.add('beau', 'person'); ht.add('fido', 'dog'); ht.add('rex', 'dinosour'); ht.add('tux', 'penguin') console.log(ht.lookup('tux')) // penguin ht.print(); // [ <1 empty item>,[ [ 'beau', 'person' ], [ 'tux', 'penguin' ] ], [ [ 'fido', 'dog' ] ], [ [ 'rex', 'dinosour' ] ] ]

Map

Map

  • In Javascript, object is map
 let myMap = function() { this.collection = {}; this.count = 0; this.size = function() { // return number of total item in map return this.count; }; this.set = function(key, value) { // add (key, value) pair to map this.collection[key] = value; this.count++; }; this.has = function(key) { // check if map contains a given key return (key in this.collection); }; this.get = function(key) { // get value given key return (key in this.collection) ? this.collection[key] : null; }; this.delete = function(key) { // delete value given key if (key in this.collection) { delete this.collection[key]; this.count--; } }; this.values = function() { // list all values in map let result = new Array(); for (let key of Object.keys(this.collection)) { result.push(this.collection[key]); }; return (result.length > 0) ? result : null; }; this.clear = function() { // delete all key value pairs in map this.collection = {}; this.count = 0; }; this.log = function() { // log the whole map out (for learning purpose) console.log(this.collection); } }; let map = new myMap(); map.set('arms', 2); map.set('fingers', 10); map.set('eyes', 2); map.set('belley button', 1); console.log(map.log()); // { arms: 2, fingers: 10, eyes: 2, 'belley button': 1 } console.log(map.get('fingers')); // 10 console.log(map.size()); // 4 console.log(map.values()); // [ 2, 10, 2, 1 ] let map2 = new myMap(); map2.set('hands', 'right'); console.log(map2.values()); // [ 'right' ] console.log(map2.has('hands')); // true let keyObj = {}, keyFunc = function() {}; map2.set('hello', 'string value'); map2.set(keyObj, 'obj value'); map2.set(keyFunc, 'func value'); map2.set(NaN, 'NaN value') console.log(map2.size); // [Function] console.log(map2.get('hello')); // string value console.log(map2.get(keyObj)); // obj value console.log(map2.get(keyFunc)); // func value console.log(map2.get(NaN)); // NaN value

Linked list

Linked list Linked list2

 const util = require('util') function LinkedList() { let length = 0; let head = null; let Node = function(element) { // define a node in the linked list this.element = element; this.next = null; } this.size = function() { return length } // get linked list length this.head = function() { return head } // return head of the linked list this.add = function(element) { // add element to linked list let node = new Node(element); if(head === null) { head = node } else { let currentNode = head; while(currentNode.next) { currentNode = currentNode.next; } currentNode.next = node; } length++; } this.remove = function(element) { // remove an element from the linked list by its data let currentNode = head; let previousNode; if(currentNode.element === element) { head = currentNode.next; } else { while(currentNode.element !== element) { previousNode = currentNode; currentNode = currentNode.next; } previousNode.next = currentNode.next; } length--; } this.isEmpty = function() { return length == 0 } // check if linked list is empty this.indexOf = function(element) { // get index of an element let currentNode = head; let index = 0; // function return -1 if element is not in the linked list if(currentNode.element === element) { return index; } else { while(currentNode.element !== element) { currentNode = currentNode.next; index++; } if(currentNode !== null) { return index } else { return -1 } } } this.elementAt = function(index) { // get element by index let currentNode = head; let currentIndex = 0; while(currentNode && index !== currentIndex) { currentNode = currentNode.next; currentIndex++; } if(currentNode) { return currentNode.element } else { return -1; } } this.addAt = function(index, element) { // add element at given index let node = new Node(element); let currentNode = head; let currentIndex = 0; let previousNode; if(index > length - 1) { return 'index out of range!' } else { if(index === 0) { node.next = head; head = node; length++; return } while(index !== currentIndex) { previousNode = currentNode; currentNode = currentNode.next; currentIndex++ } previousNode.next = node; node.next = currentNode; length++; } } this.removeAt = function(index) { // remove element at index let currentNode = head; let currentIndex = 0; let previousNode; if(index > length - 1) { return 'index out of range!' } else { if(index === 0) { head = head.next; length--; return } while(index !== currentIndex) { previousNode = currentNode; currentNode = currentNode.next; currentIndex++ } previousNode.next = currentNode.next; length--; } } } let myll = new LinkedList(); console.log(myll.size()); // 0 console.log(myll.head()); // null myll.add(12); console.log(myll.size()); // 1 myll.add(34); console.log(myll.size()); // 2 console.log(myll.head()); // Node {element:12,next:Node{ element: 34, next: null } } myll.add(76); myll.add(43); console.log(myll.size()); // 4 myll.remove(76); console.log(myll.size()); // 3 console.log(myll.indexOf(34)); // 1 console.log(myll.elementAt(4)); // -1 console.log(myll.head()); // Node {element:12,next:Node{element:34,next Node{element:43,next:null}}} console.log(myll.addAt(7, 'lalala')); // index out of range! console.log(myll.addAt(0, 'lalala')); // undefined console.log(myll.addAt(2, 'lolo')); // undefined console.log(util.inspect(myll.head(), {showHidden: false, depth: null})); // Node {element: 'lalala',next: Node {element: 12,next:Node {element: 'lolo',next: Node { element: 34, next: Node { element: 43, next: null } } } } } console.log(myll.removeAt(2)); // undefined console.log(util.inspect(myll.head(), {showHidden: false, depth: null})); // Node {element: 'lalala',next: Node {element: 12,next: Node { element: 34, next: Node { element: 43, next: null } } } }

Trie

Trie

  • An use case is to validate if a word in the dictionary
 const Node = function() { this.keys = new Map(); this.end = false; this.setEnd = function() { this.end = true }; this.isEnd = function() { return this.end }; } let Trie = function() { this.root = new Node(); this.add = function(input, node = this.root) { // add word to trie if (input.length == 0) { node.setEnd(); return; } else if (!node.keys.has(input[0])) { node.keys.set(input[0], new Node()); return this.add(input.substr(1), node.keys.get(input[0])); } else { return this.add(input.substr(1), node.keys.get(input[0])); }; }; this.isWord = function(word) { // check if word is in trie let node = this.root; while (word.length > 1) { if (!node.keys.has(word[0])) { return false; } else { node = node.keys.get(word[0]); word = word.substr(1); }; }; return (node.keys.has(word) && node.keys.get(word).isEnd()) ? true : false; }; this.print = function() { let words = new Array(); let search = function(node, string) { if (node.keys.size != 0) { for (let letter of node.keys.keys()) { search(node.keys.get(letter), string.concat(letter)); }; if (node.isEnd()) { words.push(string); }; } else { string.length > 0 ? words.push(string) : undefined; return; }; }; search(this.root, new String()); return words.length > 0 ? words : mo; }; }; myTrie = new Trie() myTrie.add('ball'); myTrie.add('bat'); myTrie.add('doll'); myTrie.add('dork'); myTrie.add('do'); myTrie.add('dorm') myTrie.add('send') myTrie.add('sense') console.log(myTrie.isWord('doll')); // true console.log(myTrie.isWord('dor')) // false console.log(myTrie.isWord('dorf')) // false console.log(myTrie.print()); // [ 'ball', 'bat', 'doll', 'dork', 'dorm', 'do', 'send', 'sense' ]

Heap

Heap

  • Partially ordered binary tree which satisfies the heap property.
  • Heap property indicates a specific relationship between parent and child node
  • Max heap: all parent nodes are greater than or equal to child nodes
  • Min heap: all child nodes are greater than or equal to parent nodes
  • The order between child nodes in a same level does not matter
  • Binary heaps are complete binary trees: all levels of the tree are fully filled (if the last level partially filled, it's filled from left to right)
  • In array representation, index start at 1 so index 0 is null
  • Node at index k has left child node at index 2*k and right child node at index 2*k+1
  • Node at index l has parent node at index roundDown(l/2)
  • Online heap and array representation
  • Online interacting heap creation
  • Heap valuable feature: min and max sorting. With the worst case performance of O(nlogn) Heap2
 const myMinHeap = new MinHeap(); myMinHeap.insert(8); myMinHeap.insert(32); myMinHeap.insert(31); myMinHeap.insert(5); myMinHeap.print(); // [ null, 5, 8, 31, 32 ] myMinHeap.insert(7); myMinHeap.insert(100); myMinHeap.print(); // [ null, 5, 7, 31, 32, 8, 100 ] console.log(myMinHeap.sort()); // [ 5, 7, 8, 31, 32, 100 ] myMinHeap.print(); // [ null ] const myMaxHeap = new MaxHeap(); myMaxHeap.insert(8); myMaxHeap.insert(32); myMaxHeap.insert(31); myMaxHeap.insert(5); myMaxHeap.print(); // [ null, 32, 8, 31, 5 ] myMaxHeap.insert(7); myMaxHeap.insert(100); myMaxHeap.print(); // [ null, 100, 8, 32, 5, 7, 31 ] console.log(myMaxHeap.sort()); // [ 100, 32, 31, 8, 7, 5 ] myMaxHeap.print(); // [ null ] function MinHeap() { let heap = [null]; this.print = function() { console.log(heap) } // print the heap array representation this.insert = function(num) { // insert a number to heap heap.push(num); if (heap.length > 2) { let idx = heap.length - 1; while (heap[idx] < heap[Math.floor(idx/2)]) { if (idx >= 1) { [heap[Math.floor(idx/2)], heap[idx]] = [heap[idx], heap[Math.floor(idx/2)]]; if (Math.floor(idx/2) > 1) { idx = Math.floor(idx/2); } else { break; }; }; }; }; }; this.remove = function() { // remove a number from heap let smallest = heap[1]; if (heap.length > 2) { heap[1] = heap[heap.length - 1]; heap.splice(heap.length - 1); if (heap.length == 3) { if (heap[1] > heap[2]) { [heap[1], heap[2]] = [heap[2], heap[1]]; }; return smallest; }; let i = 1; let left = 2 * i; let right = 2 * i + 1; while (heap[i] >= heap[left] || heap[i] >= heap[right]) { if (heap[left] < heap[right]) { [heap[i], heap[left]] = [heap[left], heap[i]]; i = 2 * i } else { [heap[i], heap[right]] = [heap[right], heap[i]]; i = 2 * i + 1; }; left = 2 * i; right = 2 * i + 1; if (heap[left] == undefined || heap[right] == undefined) { break; }; }; } else if (heap.length == 2) { heap.splice(1, 1); } else { return null; }; return smallest; }; this.sort = function() { let result = new Array(); while (heap.length > 1) { result.push(this.remove()); }; return result; }; }; function MaxHeap() { let heap = [null]; this.print = () => { console.log(heap) }; this.insert = function(num) { heap.push(num); if (heap.length > 2) { let idx = heap.length - 1; while (heap[idx] > heap[Math.floor(idx/2)]) { if (idx >= 1) { [heap[Math.floor(idx/2)], heap[idx]] = [heap[idx], heap[Math.floor(idx/2)]]; if (Math.floor(idx/2) > 1) { idx = Math.floor(idx/2); } else { break; }; }; }; }; }; this.remove = function() { let smallest = heap[1]; if (heap.length > 2) { heap[1] = heap[heap.length - 1]; heap.splice(heap.length - 1); if (heap.length == 3) { if (heap[1] < heap[2]) { [heap[1], heap[2]] = [heap[2], heap[1]]; }; return smallest; }; let i = 1; let left = 2 * i; let right = 2 * i + 1; while (heap[i] <= heap[left] || heap[i] <= heap[right]) { if (heap[left] > heap[right]) { [heap[i], heap[left]] = [heap[left], heap[i]]; i = 2 * i } else { [heap[i], heap[right]] = [heap[right], heap[i]]; i = 2 * i + 1; }; left = 2 * i; right = 2 * i + 1; if (heap[left] == undefined || heap[right] == undefined) { break; }; }; } else if (heap.length == 2) { heap.splice(1, 1); } else { return null; }; return smallest; }; this.sort = function() { let result = new Array(); while (heap.length > 1) { result.push(this.remove()); }; return result; }; };

Graph

Graph

  • Graph is collection of things and relationship between them
  • Data in graph is called node(vertices) and connection between nodes called edges
  • There are two major types of graphs: directed and undirected
  • directed graph is graph with direction (e.g. social network)
  • undirected graph is graph with direction (e.g. webpage links) Graph2
  • Representation of graph: adjacency list, adjacency matrix can represent direction, incidence matrix (row are nodes, column are edges)
const adjacencyList = [ [ 1, 2 ], // node 1 [ 0 ], // node 2 [ 2 ], // node 3 ]; const adjacencyMatrix = [ [ 0, 1, 1 ], // node 1 [ 0, 0, 0 ], // node 2 [ 1, 0, 0 ], // node 3 ] const incidenceMatrix = [ [ 0, 1, -1 ], [ 0, 0, 0 ], [ -1, 0, 0 ], ]

Graph3 Graph4

  • Graph traversal: breadth-first search, depth-first search breadth-first search
 var exBFSGraph = [ // adjagency representation of a graph [0, 1, 1, 1, 0], [0, 0, 1, 0, 0], [1, 1, 0, 0, 0], [0, 0, 0, 1, 0], [0, 1, 0, 0, 0] ]; console.log(bfs(exBFSGraph, 1)); // distance between node 1 to other nodes // { '0': 2, '1': 0, '2': 1, '3': 3, '4': Infinity } function bfs(graph, root) { var nodesLen = {}; for (var i = 0; i < graph.length; i++) { nodesLen[i] = Infinity; } nodesLen[root] = 0; var queue = [root]; var current; while (queue.length != 0) { current = queue.shift(); var curConnected = graph[current]; var neighborIdx = []; var idx = curConnected.indexOf(1); while (idx != -1) { neighborIdx.push(idx); idx = curConnected.indexOf(1, idx + 1); } for (var j = 0; j < neighborIdx.length; j++) { if (nodesLen[neighborIdx[j]] == Infinity) { nodesLen[neighborIdx[j]] = nodesLen[current] + 1; queue.push(neighborIdx[j]); } } } return nodesLen; };

Big O notation

  • Simplify analysis of algoritm's efficiency
  • Complexity in term of input size, N
  • Machine independent, basic computer step
  • Analyze time and space of worst case scenario
  • Ignore constant 5n -> O(n)
  • Cetain terms dominate others O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(2^n) < O(n!) Big O
 x = 5 + 15 * 20; // O(1) independent of input size (input are constants) x = 5 + 15 * 20; y = 9 - 6; console.log(x + y) // total time = O(1) + O(1) + O(1) = 3O(1) = O(1) (constants are dropped) for(let i = 0; i < N; i++) { console.log(i) } // total time = N * O(1) = O(N) (input now is N, not constant) y = 32 + 6 for(let i = 0; i < N; i++) { console.log(i) } // total time = O(1) + N * O(1) = O(N) (low order term is dropped) y = 32 + 6 for(let i = 0; i < N; i++) { console.log(i) } for(let i = 0; i < N; i++) { for(let j = 0; i < N; i++) { console.log(j); } } // total time = max(O(1), O(N), O(N^2)) = O(N^2) (O(N^2) dominates) if(x > 0) { // O(1) } else if(x < 0) { // O(logn) } else { // O(n^2) } // total time = O(n^2) (big O considers worst case scenario)

About

Popular data structures implemented in Javascript: stack, queue, set, priority queue, binary search tree, graph, linked list, heap, trie

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •