├── .gitignore ├── Algorithms ├── Search │ ├── BinarySearch.js │ ├── InterpolationSearch.js │ └── LinearSearch.js ├── Sorting │ ├── BubbleSort.js │ ├── BucketSort.js │ ├── CountingSort.js │ ├── HeapSort.js │ ├── InsertionSort.js │ ├── MergeSort.js │ ├── QuickSort.js │ ├── RadixSort.js │ ├── SelectionSort.js │ └── TopoSort.js └── graph │ ├── minspaningtree │ ├── Kruskal.js │ └── Prism.js │ ├── shortestpath │ ├── Dijkstra.js │ └── FloydWarshall.js │ ├── traversal │ ├── BFS.js │ └── DFS.js │ └── util.js ├── README.md ├── SUMMARY.md ├── data_structure ├── AVL.js ├── BinarySearchTree.js ├── CircularLinkedList.js ├── Dequeue.js ├── Dictionary.js ├── DoubleLinkedList.js ├── Graph.js ├── HashTable.js ├── HashTableLinearProbing.js ├── HashTableSeparateChaining.js ├── LinkedList.js ├── MaxHeap.js ├── MinHeap.js ├── Queue.js ├── RedBlackTree.js ├── Set.js ├── SortedLinkedList.js ├── Stack.js └── models │ ├── DoublyNode.js │ ├── KeyValue.js │ ├── Node.js │ ├── RedBlackNode.js │ └── TreeNode.js ├── deque.md ├── dictionary.md ├── hashtable ├── README.md ├── hashtablelinearprobing.md └── hashtableseparatechaining.md ├── index.js ├── linked-list ├── README.md ├── circularlinkedlist.md ├── doublylinkedlist.md ├── singlelinkedlist.md └── sortedlistedlist.md ├── package.json ├── problems ├── baseConvertor.js ├── hotPotateo.js └── palidrome.js ├── queue.md ├── set.md ├── stack.md ├── tests ├── LinkedListTest.js ├── QueueTest.js ├── SetTest.js └── StackTest.js └── utils └── function.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | 107 | # test files 108 | index.js 109 | 110 | 111 | #package lock file 112 | package-lock.json -------------------------------------------------------------------------------- /Algorithms/Search/BinarySearch.js: -------------------------------------------------------------------------------- 1 | const { 2 | defaultEqualFun, 3 | defaultCompare, 4 | lessOrEquals, 5 | Compare 6 | } = require('../../utils/function'); 7 | 8 | const { 9 | QuickSort 10 | } = require('../Sorting/QuickSort'); 11 | const { 12 | MergeSort 13 | } = require('../Sorting/MergeSort'); 14 | 15 | /** 16 | * 17 | * @param {Array} array 18 | * @param {any} key 19 | * @param {Function} equalFun 20 | * @param {Function} compareFun 21 | */ 22 | const BinarySearch = (array , key , equalFun = defaultEqualFun, compareFun = defaultCompare) => { 23 | const sortedArray = MergeSort(array); 24 | let low = 0; 25 | let high = sortedArray.length -1; 26 | while(lessOrEquals(low , high ,compareFun)){ 27 | let mid = Math.floor((high + low)/2); 28 | let element = sortedArray[mid]; 29 | if (compareFun(element,key) == Compare.LESS_THAN) { 30 | low = mid + 1; 31 | } else if(compareFun(element,key) == Compare.BIGGER_THAN) { 32 | high = mid - 1; 33 | }else { 34 | return true; 35 | } 36 | } 37 | return false; 38 | } 39 | 40 | // console.time('BinarySearch') 41 | // console.log(BinarySearch([ 15, 8, 0, 6, 19, 4, 13, 3, 18, 7, 9, 1, 14, 16, 17, 2, 12, 5, 11, 10 ] , 30)); 42 | // console.timeEnd('BinarySearch') 43 | 44 | module.exports = { 45 | BinarySearch 46 | } -------------------------------------------------------------------------------- /Algorithms/Search/InterpolationSearch.js: -------------------------------------------------------------------------------- 1 | const { 2 | defaultEqualFun, 3 | defaultCompare, 4 | lessOrEquals, 5 | biggerOrEquals, 6 | diffFn, 7 | Compare 8 | } = require('../../utils/function'); 9 | 10 | const { 11 | QuickSort 12 | } = require('../Sorting/QuickSort'); 13 | const { 14 | MergeSort 15 | } = require('../Sorting/MergeSort'); 16 | /** 17 | * Search an give array 18 | * Requirement 19 | * 1. Sorted 20 | * 2. Uniformly distributions [ if not then efficiency will decrease ] 21 | * @param {Array} array 22 | * @param {any} key 23 | */ 24 | const InterpolationSearch = (array, key, equalFun = defaultEqualFun, compareFun = defaultCompare) => { 25 | const sortedArray = QuickSort(array); 26 | let low = 0, 27 | high = sortedArray.length - 1; 28 | let position = -1, 29 | delta = -1; 30 | while ( 31 | low <= high && 32 | biggerOrEquals(key, sortedArray[low], compareFun) && 33 | lessOrEquals(key, sortedArray[high], compareFun) 34 | ) { 35 | delta = diffFn(key, sortedArray[low]) / diffFn(sortedArray[high], sortedArray[low]); 36 | position = low + Math.floor((high - low) * delta); 37 | if (equalFun(sortedArray[position], key)) { 38 | return true; 39 | } 40 | 41 | if (compareFun(sortedArray[position], key) == Compare.LESS_THAN) { 42 | low = position + 1; 43 | } else { 44 | high = position - 1; 45 | } 46 | } 47 | 48 | return false; 49 | } 50 | console.time('InterpolationSearch'); 51 | // console.log(InterpolationSearch([1, 10,15,50,100,89,102], 15)); 52 | // console.log(InterpolationSearch([0.0, 0.2 ,0.4, 0.6, 0.8 ,1.0, 1.2 ,1.4 ,1.6, 1.8 ,2.0 , 500 , 1000, 1500, 2000, 2500, 3000], 0.8)); 53 | console.timeEnd('InterpolationSearch'); 54 | 55 | module.exports = { 56 | InterpolationSearch 57 | } -------------------------------------------------------------------------------- /Algorithms/Search/LinearSearch.js: -------------------------------------------------------------------------------- 1 | const { 2 | defaultEqualFun 3 | } = require('../../utils/function'); 4 | 5 | /** 6 | * 7 | * @param {Array} array 8 | * @param {any} array 9 | * @param {Function} equalFun 10 | */ 11 | const LinearSearch = (array, key, equalFun = defaultEqualFun) => { 12 | for (let index = 0; index < array.length; index++) { 13 | if (equalFun(array[index], key)) { 14 | return true; 15 | } 16 | } 17 | return false; 18 | } 19 | 20 | 21 | 22 | console.time('LinearSearch') 23 | console.log(LinearSearch([1, 3, 5, 6, 8, 9, 9, 7, 89, 7], 7)); 24 | console.timeEnd('LinearSearch') 25 | 26 | 27 | module.exports = { 28 | LinearSearch 29 | } -------------------------------------------------------------------------------- /Algorithms/Sorting/BubbleSort.js: -------------------------------------------------------------------------------- 1 | const { 2 | Compare, 3 | defaultCompare, 4 | swap 5 | } = require('../../utils/function'); 6 | /** 7 | * Sort the Element in a given array 8 | * complexity of Bubble Sort is O(n^2) 9 | * @param {Array} array 10 | * @param {Function} compareFun 11 | */ 12 | const BubbleSort = (array, compareFun = defaultCompare) => { 13 | const { 14 | length 15 | } = array; 16 | let swapFlag = false; 17 | for (let i = 0; i < length; i++) { 18 | for (let j = 0; j < length - 1; j++) { 19 | if (compareFun(array[j], array[j + 1]) == Compare.BIGGER_THAN) { 20 | swap(array, j, j + 1); 21 | swapFlag = true; 22 | } 23 | 24 | if (!swapFlag) { 25 | break; 26 | } 27 | } 28 | 29 | } 30 | return array; 31 | } 32 | /** 33 | * Sort the Element in a given array 34 | * complexity of Bubble Sort is O(n^2) 35 | * Inner Loop Optimized 36 | * @param {Array} array 37 | * @param {Function} compareFun 38 | */ 39 | const BubbleSortImporved = (array, compareFun = defaultCompare) => { 40 | const { 41 | length 42 | } = array; 43 | for (let i = 0; i < length; i++) { 44 | for (let j = 0; j < length - 1 - i; j++) { 45 | if (array[j + 1] !== undefined && compareFun(array[j], array[j + 1]) == Compare.BIGGER_THAN) { 46 | swap(array, j, j + 1); 47 | } 48 | 49 | } 50 | 51 | } 52 | return array; 53 | } 54 | 55 | // console.time('BubbleSort') 56 | // console.log(BubbleSort([10, 4, 7, 3, -1, 0, -6])); 57 | // console.timeEnd('BubbleSort') 58 | // console.time('BubbleSortImporved') 59 | // console.log(BubbleSortImporved([5, 3, 10 ,1, 0, -1,7])); 60 | // console.timeEnd('BubbleSortImporved') 61 | 62 | module.exports = { 63 | BubbleSort, 64 | BubbleSortImporved 65 | } -------------------------------------------------------------------------------- /Algorithms/Sorting/BucketSort.js: -------------------------------------------------------------------------------- 1 | const { 2 | findMinMax 3 | } = require('./CountingSort'); 4 | 5 | const { 6 | MergeSort 7 | } = require('./MergeSort'); 8 | const { 9 | InsertionSort 10 | } = require('./InsertionSort'); 11 | 12 | /** 13 | * Sort the givent element in a array its distributed sorting 14 | * complexity is O(n+k) 15 | * n -> number of elements to be sorted 16 | * k -> number of buckets 17 | * @param {array} array 18 | * @param {Number} bucketsCounts 19 | * @param {Function} sortFunc 20 | */ 21 | const BucketSort = (array, bucketsCounts = 5 , sortFunc = InsertionSort) => { 22 | if (array.length < 2) { 23 | return array; 24 | } 25 | // sub divide the array into buckets 26 | const buckets = createBuckets(array, bucketsCounts); 27 | // sorted the individual bucket and merge into one 28 | return sortedBuckets(buckets,sortFunc); 29 | } 30 | 31 | /** 32 | * 33 | * @param {array} array 34 | * @param {Number} bucketsCounts 35 | */ 36 | const createBuckets = (array, bucketsCounts) => { 37 | const { 38 | min, 39 | max 40 | } = findMinMax(array); 41 | const bucketSize = Math.floor((max - min) / bucketsCounts) + 1; 42 | // Initalize the buckets 43 | const buckets = []; 44 | for (let i = 0; i < bucketSize; i++) { 45 | buckets[i] = []; 46 | } 47 | // insert the element into buckets 48 | for (let index = 0; index < array.length; index++) { 49 | // find the correct bucket to sub divide the elements into small bucket. 50 | let bucketIndex = Math.floor((array[index] - min) / bucketSize); 51 | if (!buckets[bucketIndex]) { 52 | bucketIndex -= 1; 53 | } 54 | buckets[bucketIndex].push(array[index]); 55 | } 56 | 57 | return buckets; 58 | 59 | } 60 | 61 | /** 62 | * 63 | * @param {Array} buckets 64 | * * @param {Function} sortFunc 65 | */ 66 | const sortedBuckets = (buckets,sortFun) => { 67 | const sortedBucket = []; 68 | // sort the individual sort combine into a sorted array 69 | for (let index = 0; index < buckets.length; index++) { 70 | if (buckets[index] != null) { 71 | sortedBucket.push(...sortFun(buckets[index])); 72 | } 73 | } 74 | return sortedBucket; 75 | } 76 | 77 | // console.time('BucketSort'); 78 | // console.log(BucketSort([5, 3, 10, 1, 0, -1, 7, 10, 15])); 79 | // console.timeEnd('BucketSort'); 80 | 81 | module.exports = { 82 | BucketSort 83 | } -------------------------------------------------------------------------------- /Algorithms/Sorting/CountingSort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sort the Element in a given array 3 | * complexity of Counting Sort is O(n+k) 4 | * Distributed and Interger Sorting Alogrithms 5 | * @param {Array} array 6 | */ 7 | const CountingSort = array => { 8 | if (array.length < 2) { 9 | return array; 10 | } 11 | 12 | const maxValue = findMaxValue(array); 13 | 14 | const counts = new Array(maxValue + 1); 15 | array.forEach(element => { 16 | if (!counts[element]) { 17 | counts[element] = 0; 18 | } 19 | counts[element]++; 20 | }); 21 | let sortIndexed = 0; 22 | counts.forEach((count, i) => { 23 | while (count > 0) { 24 | array[sortIndexed++] = i; 25 | count--; 26 | } 27 | }); 28 | return array; 29 | } 30 | 31 | /** 32 | * return the max. value in a given array 33 | * @param {Array} array 34 | * @returns Number 35 | */ 36 | const findMaxValue = array => { 37 | let max = array[0]; 38 | for (let index = 1; index < array.length; index++) { 39 | if (array[index] > max) { 40 | max = array[index]; 41 | } 42 | } 43 | 44 | return max; 45 | } 46 | 47 | 48 | /** 49 | * Sort the Element in a given array 50 | * complexity of Counting Sort is O(n+k) 51 | * Distributed and Interger Sorting Alogrithms 52 | * @param {Array} array 53 | */ 54 | const CountingSortForNegative = array => { 55 | if (array.length < 2) { 56 | return array; 57 | } 58 | const { 59 | min, 60 | max 61 | } = findMinMax(array); 62 | const counts = {}; 63 | array.forEach(element => { 64 | if (!counts[element]) { 65 | counts[element] = 0; 66 | } 67 | counts[element]++; 68 | }); 69 | for (let index = min, sortIndexed = 0; index <= max; index++) { 70 | while (counts[index] > 0) { 71 | array[sortIndexed++] = index; 72 | counts[index]--; 73 | } 74 | 75 | } 76 | return array; 77 | } 78 | 79 | /** 80 | * 81 | * @param {Array} array 82 | */ 83 | const findMinMax = array => { 84 | let min = Number.MAX_SAFE_INTEGER, 85 | max = array[0]; 86 | for (let index = 0; index < array.length; index++) { 87 | if (array[index] < min) { 88 | min = array[index]; 89 | } 90 | if (array[index] > max) { 91 | max = array[index]; 92 | } 93 | } 94 | 95 | return { 96 | min, 97 | max 98 | } 99 | } 100 | 101 | // console.time('CountingSort'); 102 | // console.log(CountingSortForNegative([5, 3, 3, 10, 1, 2, 0, -1, -3, 7, 7, 7, 7, 7, 7, 7])); 103 | // // console.log(CountingSortForNegative([5, 4, 3, 2, 3, 1, 0])); 104 | // console.timeEnd('CountingSort'); 105 | 106 | 107 | module.exports = { 108 | CountingSort, 109 | CountingSortForNegative, 110 | findMinMax 111 | } -------------------------------------------------------------------------------- /Algorithms/Sorting/HeapSort.js: -------------------------------------------------------------------------------- 1 | const { 2 | defaultCompare, 3 | Compare, 4 | swap 5 | } = require('../../utils/function'); 6 | 7 | /** 8 | * 9 | * @param {Array} arr 10 | * @param {Function} compareFun 11 | */ 12 | function builMaxHeap(arr, compareFun) { 13 | for (let index = (arr.length / 2) - 1; index >= 0; index--) { 14 | heapify(arr, arr.length, index, compareFun) 15 | } 16 | return arr; 17 | } 18 | 19 | /** 20 | * 21 | * @param {Array} arr 22 | * @param {Number*} length 23 | * @param {Number} index 24 | * @param {Function} compareFun 25 | */ 26 | function heapify(arr, length, index, compareFun) { 27 | let element = index; 28 | let left = (2 * index) + 1; 29 | let right = (2 * index) + 2; 30 | 31 | if (left < length && compareFun(arr[element], arr[left]) == Compare.LESS_THAN) { 32 | element = left; 33 | } 34 | if (right < length && compareFun(arr[element], arr[right]) == Compare.LESS_THAN) { 35 | element = right; 36 | } 37 | 38 | if (element != index) { 39 | swap(arr, index, element); 40 | heapify(arr, length, element, compareFun); 41 | } 42 | 43 | 44 | } 45 | 46 | /** 47 | * Sort the Element in a given array 48 | * complexity of Heap Sort is O(n*long n) 49 | * @param {Array} arr 50 | * @param {Function} compareFun 51 | */ 52 | function HeapSort(arr, compareFun = defaultCompare) { 53 | let heapSize = arr.length; 54 | builMaxHeap(arr, compareFun); 55 | while (heapSize > 1) { 56 | swap(arr, 0, --heapSize); 57 | heapify(arr, heapSize, 0, compareFun); 58 | } 59 | return arr; 60 | } 61 | 62 | 63 | module.exports = { 64 | HeapSort 65 | }; -------------------------------------------------------------------------------- /Algorithms/Sorting/InsertionSort.js: -------------------------------------------------------------------------------- 1 | const { Compare, defaultCompare } = require('../../utils/function'); 2 | 3 | /** 4 | * Sort the Element in a given array 5 | * complexity of Insertion Sort is O(n^2) 6 | * @param {array} array 7 | * @param {Function} compareFunc 8 | * @returns array 9 | */ 10 | const InsertionSort = (array, compareFunc = defaultCompare) => { 11 | const { length } = array; 12 | let i, j, temp; 13 | for (let i = 1; i < length; i++) { 14 | j = i; 15 | temp = array[j]; 16 | while (j > 0 && compareFunc(array[j - 1], temp) == Compare.BIGGER_THAN) { 17 | array[j] = array[j - 1]; 18 | j--; 19 | } 20 | array[j] = temp; 21 | } 22 | return array; 23 | } 24 | 25 | // console.time('InsertionSort') 26 | // console.log(InsertionSort([5, 3, 10 ,1, 0, -1,7])); 27 | // console.timeEnd('InsertionSort') 28 | module.exports = { 29 | InsertionSort 30 | } 31 | -------------------------------------------------------------------------------- /Algorithms/Sorting/MergeSort.js: -------------------------------------------------------------------------------- 1 | const { 2 | Compare, 3 | defaultCompare 4 | } = require('../../utils/function'); 5 | 6 | /** 7 | * Sort the Element in a given array 8 | * complexity of Merge Sort is O(n*long n) 9 | * @param {array} array 10 | * @param {Function} compareFunc 11 | * @returns array 12 | */ 13 | const MergeSort = (array, compareFunc = defaultCompare) => { 14 | if (array.length > 1) { 15 | const { 16 | length 17 | } = array; 18 | const middle = Math.floor(length / 2); 19 | const left = MergeSort(array.slice(0, middle), compareFunc); 20 | const right = MergeSort(array.slice(middle, length), compareFunc); 21 | array = merge(left, right, compareFunc); 22 | 23 | } 24 | return array; 25 | } 26 | 27 | /** 28 | * Merge Two Array 29 | * @param {Array} left 30 | * @param {Array} right 31 | * @param {Function} compareFunc 32 | */ 33 | const merge = (left, right, compareFunc) => { 34 | let i = 0, 35 | j = 0; 36 | const result = []; 37 | while (i < left.length && j < right.length) { 38 | result.push(compareFunc(left[i], right[j]) == Compare.LESS_THAN ? left[i++] : right[j++]); 39 | } 40 | return result.concat(i < left.length ? left.slice(i) : right.slice(j)); 41 | } 42 | 43 | // console.time('MergeSort'); 44 | // console.log(MergeSort([5, 3, 10, 1, 2, 0, -1, 7])); 45 | // console.timeEnd('MergeSort'); 46 | module.exports = { 47 | MergeSort 48 | } -------------------------------------------------------------------------------- /Algorithms/Sorting/QuickSort.js: -------------------------------------------------------------------------------- 1 | const { 2 | Compare, 3 | defaultCompare, 4 | swap 5 | } = require('../../utils/function'); 6 | 7 | /** 8 | * Sort the Element in a given array 9 | * complexity of Quick Sort is O(n*long n) 10 | * @param {array} array 11 | * @param {Function} compareFunc 12 | * @returns array 13 | */ 14 | const QuickSort = (array, compareFunc = defaultCompare) => { 15 | return quick(array, 0, array.length - 1, compareFunc); 16 | } 17 | 18 | 19 | const quick = (array, left, right, compareFunc) => { 20 | let index; 21 | if (array.length > 1) { 22 | index = partition(array, left, right, compareFunc); 23 | if (left < index - 1) { 24 | quick(array, left, index - 1, compareFunc); 25 | } 26 | if (index < right) { 27 | quick(array, index, right, compareFunc); 28 | } 29 | } 30 | return array; 31 | } 32 | 33 | const partition = (array, left, right, compareFunc) => { 34 | const pivot = array[Math.floor((left + right) / 2)]; 35 | let i = left , j =right ; 36 | while (i <= j) { 37 | while (compareFunc(array[i], pivot) == Compare.LESS_THAN) { 38 | i++; 39 | } 40 | while (compareFunc(array[j], pivot) == Compare.BIGGER_THAN) { 41 | j--; 42 | } 43 | if (i <= j) { 44 | swap(array, i, j); 45 | i++; 46 | j--; 47 | } 48 | } 49 | return i; 50 | } 51 | 52 | 53 | // console.time('QuickSort'); 54 | // console.log(QuickSort([5, 3, 10, 1, 2, 0, -1, 7])); 55 | // console.timeEnd('QuickSort'); 56 | module.exports = { 57 | QuickSort 58 | } -------------------------------------------------------------------------------- /Algorithms/Sorting/RadixSort.js: -------------------------------------------------------------------------------- 1 | const { 2 | findMinMax 3 | } = require('./CountingSort') 4 | /** 5 | * Sort the Element in a given array 6 | * complexity of Radix Sort is O d(n+k) 7 | * Distributed and Interger Sorting Alogrithms 8 | * @param {Array} array 9 | * @param {Number} radixBase 10 | */ 11 | const RadixSort = (array, radixBase = 10) => { 12 | if (array.length < 2) { 13 | return array; 14 | } 15 | const { 16 | min, 17 | max 18 | } = findMinMax(array); 19 | let significantDigit = 1; 20 | while (((max - min) / significantDigit) >= 1) { 21 | array = createCountRadixSort(array, min, significantDigit, radixBase); 22 | significantDigit *= radixBase; 23 | } 24 | return array; 25 | } 26 | 27 | /** 28 | * 29 | * @param {Array} array 30 | * @param {Number} minValue 31 | * @param {Number} significantDigit 32 | * @param {Number} radixBase 33 | */ 34 | const createCountRadixSort = (array, minValue, significantDigit, radixBase) => { 35 | const bucket = []; 36 | const aux = []; 37 | let bucketIndex; 38 | 39 | // Intialize the buckets 40 | for (let index = 0; index < radixBase; index++) { 41 | bucket[index] = 0; 42 | } 43 | // counting sort based on the significant digit of the numbers that are in array 44 | for (let index = 0; index < array.length; index++) { 45 | bucketIndex = Math.floor(((array[index] - minValue) / significantDigit) % radixBase); 46 | bucket[bucketIndex]++; 47 | } 48 | // compute the cumulates so we have a correct count 49 | for (let index = 1; index < radixBase; index++) { 50 | bucket[index] += bucket[index - 1]; 51 | } 52 | //we will retrieve its significant digit again and will move its value to the aux array (subtracting the count from the buckets array ) 53 | for (let index = array.length - 1; index >= 0; index--) { 54 | bucketIndex = Math.floor(((array[index] - minValue) / significantDigit) % radixBase); 55 | aux[--bucket[bucketIndex]] = array[index]; 56 | } 57 | return aux; 58 | } 59 | 60 | 61 | console.time('RadixSort') 62 | console.log(RadixSort([1, 9, 3, 5, 7,20 ,8,62, 4, 5 ,15,101])) 63 | console.timeEnd('RadixSort'); 64 | module.exports = { 65 | RadixSort 66 | } -------------------------------------------------------------------------------- /Algorithms/Sorting/SelectionSort.js: -------------------------------------------------------------------------------- 1 | const { 2 | Compare, 3 | defaultCompare, 4 | swap 5 | } = require('../../utils/function'); 6 | 7 | /** 8 | * Sort the Element in a given array 9 | * complexity of Selection Sort is O(n^2) 10 | * @param {Array} array 11 | * @param {Function} compareFun 12 | */ 13 | const SelectionSort = (array, compareFun = defaultCompare) => { 14 | const { 15 | length 16 | } = array; 17 | 18 | let minIndex; 19 | for (let i = 0; i < length - 1; i++) { 20 | minIndex = i; 21 | for (let j = i; j < length; j++) { 22 | if (compareFun(array[minIndex], array[j]) == Compare.BIGGER_THAN) { 23 | minIndex = j; 24 | } 25 | } 26 | if (i !== minIndex) { 27 | swap(array, i, minIndex); 28 | } 29 | 30 | } 31 | 32 | 33 | return array; 34 | 35 | } 36 | // console.time('SelectionSort') 37 | // console.log(SelectionSort([5, 3, 10 ,1, 0, -1,7])); 38 | // console.timeEnd('SelectionSort') 39 | 40 | module.exports = { 41 | SelectionSort 42 | } -------------------------------------------------------------------------------- /Algorithms/Sorting/TopoSort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * complexity of Topo/Top Sort is O(v+e) 3 | * v -> Vertices of graph 4 | * e -> Edges of graph 5 | * @param {*} graph 6 | */ 7 | const topSort = graph => { 8 | const vertices = graph.getVertices(); 9 | const adjList = graph.getEdges(); 10 | const visited = new Set(); 11 | const ordering = []; 12 | const index = vertices - 1; 13 | 14 | for (let index = 0; index < vertices.length; index++) { 15 | let visitedNode = [] 16 | const vertex = vertices[index]; 17 | if (!visited.has(vertex)) { 18 | dfs(vertex, visited, visitedNode, adjList); 19 | } 20 | for (let index = 0; index < visitedNode.length; index++) { 21 | ordering.push(visitedNode[index]); 22 | } 23 | 24 | } 25 | 26 | return ordering; 27 | } 28 | 29 | 30 | /** 31 | * 32 | * @param {*} vertex 33 | * @param {*} visited 34 | * @param {*} visitedNode 35 | * @param {*} adjList 36 | */ 37 | const dfs = (vertex, visited, visitedNode, adjList) => { 38 | visited.add(vertex); 39 | 40 | const neighbores = adjList.get(vertex); 41 | for (let index = 0; index < neighbores.length; index++) { 42 | const node = neighbores[index]; 43 | if (!visited.has(node)) { 44 | dfs(node, visited, visitedNode, adjList) 45 | } 46 | } 47 | visitedNode.push(vertex); 48 | } 49 | 50 | 51 | /* 52 | 53 | const graphA = new Graph(true); // directed graph 54 | let myVerticesA = ['A', 'B', 'C', 'D', 'E', 'F']; 55 | for (i = 0; i < myVerticesA.length; i++) { 56 | graph.addVertex(myVerticesA[i]); 57 | } 58 | graphA.addEdge('A', 'D'); 59 | graphA.addEdge('A', 'C'); 60 | graphA.addEdge('B', 'D'); 61 | graphA.addEdge('B', 'E'); 62 | graphA.addEdge('C', 'F'); 63 | graphA.addEdge('F', 'E'); 64 | 65 | */ 66 | 67 | module.exports = { 68 | topSort 69 | } -------------------------------------------------------------------------------- /Algorithms/graph/minspaningtree/Kruskal.js: -------------------------------------------------------------------------------- 1 | const INF = Number.MAX_SAFE_INTEGER; 2 | const Kruskal = graph => { 3 | let ne = 0; 4 | let a, b, u, v; 5 | const parent = []; 6 | const { 7 | length 8 | } = graph; 9 | const cost = InitializeCost(graph, length); 10 | while (ne < length-1) { 11 | for (let i = 0 , min = INF; i < length; i++) { 12 | for (let j = 0; j < length; j++) { 13 | if (cost[i][j] < min) { 14 | min = cost[i][j]; 15 | a = u = i; 16 | b = v = j; 17 | } 18 | 19 | } 20 | } 21 | u = find(u, parent); 22 | v = find(v , parent); 23 | if (union(u,v,parent)) { 24 | ne ++; 25 | } 26 | cost[a][b] = cost[b][a] = INF; 27 | } 28 | 29 | return parent; 30 | } 31 | 32 | 33 | 34 | // var graph = [ 35 | // [0, 2, 4, 0, 0, 0], 36 | // [2, 0, 2, 4, 2, 0], 37 | // [4, 2, 0, 0, 3, 0], 38 | // [0, 4, 0, 0, 3, 2], 39 | // [0, 2, 3, 3, 0, 2], 40 | // [0, 0, 0, 2, 2, 0] 41 | // ]; 42 | 43 | 44 | // console.log(Kruskal(graph)); 45 | 46 | module.exports = { 47 | Kruskal 48 | } -------------------------------------------------------------------------------- /Algorithms/graph/minspaningtree/Prism.js: -------------------------------------------------------------------------------- 1 | const INF = Number.MAX_SAFE_INTEGER; 2 | 3 | /** 4 | * 5 | * @param {Array} graph 6 | */ 7 | const Prism = graph => { 8 | const key = []; 9 | const parent = []; 10 | const visited = []; 11 | const { 12 | length 13 | } = graph; 14 | 15 | for (let v = 0; v < length; v++) { 16 | key[v] = INF; 17 | visited[v] = false; 18 | } 19 | key[0] = 0; 20 | parent[0] = -1; 21 | for (let index = 0; index < length; index++) { 22 | const u = minKey(graph, visited, key); 23 | visited[u] = true; 24 | for (let v = 0; v < length; v++) { 25 | if (graph[u][v] && !visited[v] && graph[u][v] < key[v]) { 26 | parent[v] = u; 27 | key[v] = graph[u][v]; 28 | } 29 | } 30 | } 31 | 32 | return { 33 | parent , 34 | key 35 | }; 36 | } 37 | 38 | 39 | const minKey = (graph, visited, key) => { 40 | let min = INF; 41 | let minIndex = -1; 42 | for (let v = 0; v < graph.length; v++) { 43 | if (visited[v] === false && key[v] <= min) { 44 | min = key[v]; 45 | minIndex = v; 46 | } 47 | } 48 | 49 | return minIndex; 50 | } 51 | 52 | 53 | /* var graph = [ 54 | [0, 2, 4, 0, 0, 0], 55 | [2, 0, 2, 4, 2, 0], 56 | [4, 2, 0, 0, 3, 0], 57 | [0, 4, 0, 0, 3, 2], 58 | [0, 2, 3, 3, 0, 2], 59 | [0, 0, 0, 2, 2, 0] 60 | ]; 61 | 62 | 63 | console.log(Prism(graph)); 64 | */ 65 | 66 | 67 | module.exports = { 68 | Prism 69 | } -------------------------------------------------------------------------------- /Algorithms/graph/shortestpath/Dijkstra.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @param {Graph} graph must be adjacent matrix. 4 | * @param {string} src 5 | */ 6 | 7 | const INF = Number.MAX_SAFE_INTEGER; 8 | 9 | const Dijkstra = (graph, src) => { 10 | const distance = 0; 11 | const { 12 | length 13 | } = graph; 14 | const visited = []; 15 | 16 | // Initalize the Distance and visited to false 17 | for (let index = 0; index < length; index++) { 18 | distance[index] = INF; 19 | visited[index] = false; 20 | } 21 | // set distance to src to zero i.e distance to itself will be 22 | distance[src] = 0; 23 | for (let i = 0; i < length; i++) { 24 | const u = minShortPath(distance, visited); 25 | visited[i] = true; 26 | for (let v = 0; v < length; v++) { 27 | if (!visited[v] && graph[u][v] != 0 && distance[u] !== INF && distance[u] + graph[u][v] < distance[v]) { 28 | distance[v] = distance[u] + graph[u][v]; 29 | } 30 | 31 | 32 | } 33 | 34 | } 35 | 36 | return distance; 37 | } 38 | 39 | const minShortPath = (distance, visited) => { 40 | let min = INF; 41 | let minIndex = -1; 42 | for (let v = 0; v < distance.length; v++) { 43 | if (visited[v] === false && distance[v] <= min) { 44 | min = dist[v]; 45 | minIndex = v; 46 | } 47 | } 48 | return minIndex; 49 | } 50 | 51 | /* var graph = [ 52 | [0, 2, 4, 0, 0, 0], 53 | [0, 0, 1, 4, 2, 0], 54 | [0, 0, 0, 0, 3, 0], 55 | [0, 0, 0, 0, 0, 2], 56 | [0, 0, 0, 3, 0, 2], 57 | [0, 0, 0, 0, 0, 0] 58 | ]; 59 | 60 | 61 | console.log(Dijkstra(graph, 0)); 62 | */ 63 | module.exports = { 64 | Dijkstra 65 | } -------------------------------------------------------------------------------- /Algorithms/graph/shortestpath/FloydWarshall.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @param {Graph} graph 4 | * @param {string} src 5 | */ 6 | /* 7 | Algo 8 | Create a |V| x |V| matrix, M, that will describe the distances between vertices 9 | For each cell (i, j) in M: 10 | if i == j: 11 | M[i][j] = 0 12 | if (i, j) is an edge in E: 13 | M[i][j] = weight(i, j) 14 | else: 15 | M[i][j] = infinity 16 | 17 | for k from 1 to |V|: 18 | for i from 1 to |V|: 19 | for j from 1 to |V|: 20 | if M[i][j] > M[i][k] + M[k][j]: 21 | M[i][j] = M[i][k] + M[k][j] 22 | 23 | 24 | Floyd-Warshall O(|V|^{3})O(∣V∣ ) 25 | 26 | 27 | 28 | */ 29 | const FloyWarshall = (graph) => { 30 | const distance = []; 31 | const { 32 | length 33 | } = graph; 34 | // Initalize the Distance 35 | for (let i = 0; i < length; i++) { 36 | distance[i] = []; 37 | for (let j = 0; j < length; j++) { 38 | if (i === j) { 39 | distance[i][j] = 0; 40 | } else if (graph[i][j] > 0) { 41 | distance[i][j] = graph[i][j]; 42 | } else { 43 | distance[i][j] = Infinity; 44 | } 45 | 46 | } 47 | 48 | } 49 | 50 | for (let k = 0; k < length; k++) { 51 | for (let i = 0; i < length; i++) { 52 | for (let j = 0; j < length; j++) { 53 | if (distance[i][k] + distance[k][j] < distance[i][j]) { 54 | distance[i][j] = distance[i][k] + distance[k][j]; 55 | 56 | } 57 | 58 | } 59 | 60 | } 61 | 62 | } 63 | 64 | 65 | 66 | 67 | return distance; 68 | } 69 | 70 | 71 | 72 | /* var graph = [ 73 | [0, 2, 4, 0, 0, 0], 74 | [0, 0, 1, 4, 2, 0], 75 | [0, 0, 0, 0, 3, 0], 76 | [0, 0, 0, 0, 0, 2], 77 | [0, 0, 0, 3, 0, 2], 78 | [0, 0, 0, 0, 0, 0] 79 | ]; 80 | 81 | console.log(FloyWarshall(graph)); 82 | */ 83 | 84 | 85 | module.exports = { 86 | FloyWarshall 87 | } -------------------------------------------------------------------------------- /Algorithms/graph/traversal/BFS.js: -------------------------------------------------------------------------------- 1 | const { 2 | colorInitialize, 3 | Colors 4 | } = require('../util') 5 | const { 6 | Queue 7 | } = require('./Queue'); 8 | 9 | const { 10 | StackObject 11 | } = require('./Stack') 12 | 13 | 14 | 15 | /** 16 | * 17 | * @param {*} graph 18 | * @param {*} initialVertice 19 | * @param {*} callback 20 | */ 21 | 22 | const BFS = (graph, initialVertice, callback) => { 23 | const vertices = graph.getVertices(); 24 | const adjList = graph.getEdges(); 25 | const color = colorInitialize(vertices); 26 | const queue = new Queue(); 27 | queue.equeue(initialVertice); 28 | while (!queue.isEmpty()) { 29 | const vertex = queue.dequeue(); 30 | color[vertex] = Colors.GREY; 31 | let neighbores = adjList.get(vertex); 32 | 33 | neighbores.forEach(node => { 34 | if (color[node] === Colors.WHITE) { 35 | queue.equeue(node); 36 | color[node] = Colors.GREY; 37 | } 38 | }); 39 | color[vertex] = Colors.BLACK; 40 | if (callback) { 41 | callback(vertex); 42 | } 43 | } 44 | } 45 | 46 | 47 | /** 48 | * 49 | * @param {*} graph 50 | * @param {*} initialVertice 51 | */ 52 | const BFSShortPath = (graph, initialVertice) => { 53 | const vertices = graph.getVertices(); 54 | const adjList = graph.getEdges(); 55 | const distance = {}; 56 | const predecessors = {}; 57 | const queue = new Queue(); 58 | const color = colorInitialize(vertices); 59 | // initailize the distance and predecessors; 60 | for (let index = 0; index < vertices.length; index++) { 61 | distance[vertices[index]] = 0; 62 | predecessors[vertices[index]] = null; 63 | } 64 | queue.equeue(initialVertice); 65 | while (!queue.isEmpty()) { 66 | const vertex = queue.dequeue(); 67 | let neighbores = adjList.get(vertex); 68 | color[vertex] = Colors.GREY; 69 | neighbores.forEach(vertexN => { 70 | if (color[vertexN] == Colors.WHITE) { 71 | queue.equeue(vertexN); 72 | color[vertexN] = Colors.GREY; 73 | /* Short */ 74 | predecessors[vertexN] = vertex; 75 | distance[vertexN] = distance[vertex] + 1; 76 | } 77 | 78 | color[vertex] = Colors.BLACK; 79 | }) 80 | } 81 | 82 | const fromVertex = vertices[0]; 83 | for (let index = 1; index < vertices.length; index++) { 84 | const toVertex = vertices[index]; 85 | const stack = new StackObject(); 86 | 87 | for (let v = toVertex; v != fromVertex; v = predecessors[v]) { 88 | stack.push(v); 89 | } 90 | 91 | stack.push(fromVertex); 92 | let s = stack.pop(); 93 | while (!stack.isEmpty()) { 94 | s += ` -> ${stack.pop()}` 95 | } 96 | 97 | console.log(s) 98 | } 99 | 100 | 101 | 102 | // return { 103 | // distance, 104 | // predecessors 105 | // } 106 | } 107 | 108 | /* 109 | 110 | const { Graph } = require('../../../data_structure/Graph'); 111 | 112 | const graph = new Graph(); 113 | const myVertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']; // {12} 114 | for (let i = 0; i < myVertices.length; i++) { 115 | graph.addVertex(myVertices[i]); 116 | } 117 | graph.addEdge('A', 'B'); 118 | graph.addEdge('A', 'C'); 119 | graph.addEdge('A', 'D'); 120 | graph.addEdge('C', 'D'); 121 | graph.addEdge('C', 'G'); 122 | graph.addEdge('D', 'G'); 123 | graph.addEdge('D', 'H'); 124 | graph.addEdge('B', 'E'); 125 | graph.addEdge('B', 'F'); 126 | graph.addEdge('E', 'I'); 127 | 128 | 129 | // BFS(graph,myVertices[0], (x) => console.log("Vertex Visited : ",x)); 130 | 131 | // BFSShortPath(graph, myVertices[0]); 132 | 133 | 134 | 135 | */ 136 | module.exports = { 137 | BFS, 138 | BFSShortPath 139 | } -------------------------------------------------------------------------------- /Algorithms/graph/traversal/DFS.js: -------------------------------------------------------------------------------- 1 | const { 2 | colorInitialize, 3 | Colors 4 | } = require('../util'); 5 | /** 6 | * 7 | * @param {*} graph 8 | * @param {*} callback 9 | */ 10 | const DFS = (graph, callback) => { 11 | const vertices = graph.getVertices(); 12 | const adjList = graph.getEdges(); 13 | const color = colorInitialize(vertices); 14 | 15 | // for (let index = 0; index < vertices.length; index++) { 16 | for (let index = vertices.length - 1; index > 0; index--) { 17 | if (color[vertices[index]] == Colors.WHITE) { 18 | DFSeachVisited(vertices[index], color, adjList, callback); 19 | } 20 | } 21 | } 22 | 23 | /** 24 | * 25 | * @param {*} vertices 26 | * @param {*} colors 27 | * @param {*} adjList 28 | * @param {*} callback 29 | */ 30 | const DFSeachVisited = (vertices, colors, adjList, callback) => { 31 | colors[vertices] = Colors.GREY; 32 | if (callback) { 33 | callback(vertices); 34 | } 35 | const neighbores = adjList.get(vertices); 36 | for (let index = 0; index < neighbores.length; index++) { 37 | if (colors[neighbores[index]] == Colors.WHITE) { 38 | DFSeachVisited(neighbores[index], colors, adjList, callback); 39 | } 40 | } 41 | colors[vertices] = Colors.BLACK; 42 | } 43 | 44 | 45 | /** 46 | * 47 | * @param {*} graph 48 | */ 49 | const DFSExplore = (graph) => { 50 | const vertices = graph.getVertices(); 51 | const adjList = graph.getEdges(); 52 | const color = colorInitialize(vertices); 53 | const discoveryTime = {}; 54 | const finishTime = {}; 55 | const predecessors = {}; 56 | const time = { 57 | count: 0 58 | }; 59 | 60 | for (let index = 0; index < vertices.length; index++) { 61 | const vertex = vertices[index]; 62 | discoveryTime[vertex] = 0; 63 | finishTime[vertex] = 0; 64 | predecessors[vertex] = null; 65 | } 66 | 67 | for (let index = 0; index < vertices.length; index++) { 68 | if (color[vertices[index]] == Colors.WHITE) { 69 | DFSeachExploreVisited(vertices[index], color, adjList, discoveryTime, finishTime, predecessors, time); 70 | } 71 | } 72 | 73 | return { 74 | discoveryTime, 75 | finishTime, 76 | predecessors 77 | } 78 | } 79 | 80 | /** 81 | * 82 | * @param {*} vertices 83 | * @param {*} colors 84 | * @param {*} adjList 85 | * @param {*} discoveryTime 86 | * @param {*} finishTime 87 | * @param {*} predecessors 88 | * @param {*} time 89 | */ 90 | const DFSeachExploreVisited = (vertices, colors, adjList, discoveryTime, finishTime, predecessors, time) => { 91 | colors[vertices] = Colors.GREY; 92 | discoveryTime[vertices] = ++time.count; 93 | const neighbores = adjList.get(vertices); 94 | for (let index = 0; index < neighbores.length; index++) { 95 | if (colors[neighbores[index]] == Colors.WHITE) { 96 | predecessors[neighbores[index]] = vertices; 97 | DFSeachExploreVisited(neighbores[index], colors, adjList, discoveryTime, finishTime, predecessors, time); 98 | } 99 | } 100 | colors[vertices] = Colors.BLACK; 101 | finishTime[vertices] = ++time.count; 102 | } 103 | 104 | 105 | /* 106 | const { Graph } = require('../../../data_structure/Graph'); 107 | const graph = new Graph(); 108 | const myVertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']; // {12} 109 | for (let i = 0; i < myVertices.length; i++) { 110 | graph.addVertex(myVertices[i]); 111 | } 112 | graph.addEdge('A', 'B'); 113 | graph.addEdge('A', 'C'); 114 | graph.addEdge('A', 'D'); 115 | graph.addEdge('C', 'D'); 116 | graph.addEdge('C', 'G'); 117 | graph.addEdge('D', 'G'); 118 | graph.addEdge('D', 'H'); 119 | graph.addEdge('B', 'E'); 120 | graph.addEdge('B', 'F'); 121 | graph.addEdge('E', 'I'); 122 | 123 | 124 | // DFS(graph, (x) => console.log(x)); 125 | 126 | // console.log(DFSExplore(graph)); 127 | 128 | // Path Exploring 129 | const graphA = new Graph(true); // directed graph 130 | let myVerticesA = ['A', 'B', 'C', 'D', 'E', 'F']; 131 | for (i = 0; i < myVerticesA.length; i++) { 132 | graph.addVertex(myVerticesA[i]); 133 | } 134 | graphA.addEdge('A', 'D'); 135 | graphA.addEdge('A', 'C'); 136 | graphA.addEdge('B', 'D'); 137 | graphA.addEdge('B', 'E'); 138 | graphA.addEdge('C', 'F'); 139 | graphA.addEdge('F', 'E'); 140 | const result = DFSExplore(graphA); 141 | 142 | 143 | const fTimes = result.finishTime; 144 | const s = []; 145 | for (let count = 0; count < myVerticesA.length; count++) { 146 | let max = 0; 147 | let maxName = null; 148 | for (i = 0; i < myVerticesA.length; i++) { 149 | if (fTimes[myVerticesA[i]] > max) { 150 | max = fTimes[myVerticesA[i]]; 151 | maxName = myVerticesA[i]; 152 | } 153 | } 154 | s.push(maxName); 155 | delete fTimes[maxName]; 156 | } 157 | 158 | 159 | */ 160 | 161 | module.exports = { 162 | DFS, 163 | DFSExplore 164 | } -------------------------------------------------------------------------------- /Algorithms/graph/util.js: -------------------------------------------------------------------------------- 1 | 2 | const Colors = { 3 | WHITE: 0, //Vertex not visted 4 | GREY: 1, //Vertex visted but not explored 5 | BLACK: 2 //Vertex explored Complete 6 | } 7 | 8 | const colorInitialize = vertices => { 9 | const colors = {}; 10 | vertices.forEach(vertex => { 11 | colors[vertex] = Colors.WHITE; 12 | }); 13 | 14 | return colors; 15 | } 16 | 17 | 18 | module.exports = { 19 | colorInitialize, 20 | Colors 21 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learning Data Structure & Algorithms 2 | 3 | ### What are Data Structures? 4 | 5 | > _Data Structure is a way of organizing the data so that data can be retrieved effectively._ 6 | 7 | ### List Of Data Structures. 8 | 9 | * [Stack](stack.md) 10 | * [Queue](queue.md) 11 | * [Deque](deque.md) 12 | * Linked List 13 | * [Single Linked List](linked-list/singlelinkedlist.md) 14 | * [Doubly Linked List](linked-list/doublylinkedlist.md) 15 | * [Circular Linked List](linked-list/circularlinkedlist.md) 16 | * [Sorted Linked List](linked-list/sortedlistedlist.md) 17 | * [Sets](set.md) 18 | * [Dictionary](dictionary.md) 19 | * [Hash Table](hashtable/README.md) 20 | * Separate Chain 21 | * Linear Probing 22 | * Tree 23 | * Binary Tree 24 | * Self Balancing Tree 25 | * AVL Tree 26 | * RedBlack Tree 27 | * Graph 28 | 29 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | * [Learning Data Structure & Algorithms](README.md) 4 | * [Stack](stack.md) 5 | * [Queue](queue.md) 6 | * [Deque](deque.md) 7 | * [Linked List](linked-list/README.md) 8 | * [Single Linked List](linked-list/singlelinkedlist.md) 9 | * [DoublyLinkedList](linked-list/doublylinkedlist.md) 10 | * [Circular linked list](linked-list/circularlinkedlist.md) 11 | * [SortedListedList](linked-list/sortedlistedlist.md) 12 | * [Set](set.md) 13 | * [Dictionary](dictionary.md) 14 | * [HashTable](hashtable/README.md) 15 | * [What is HashTable Linear Probing ?](hashtable/hashtablelinearprobing.md) 16 | * [HashTableSeparateChaining](hashtable/hashtableseparatechaining.md) 17 | 18 | -------------------------------------------------------------------------------- /data_structure/AVL.js: -------------------------------------------------------------------------------- 1 | const { 2 | BinarySearchTree 3 | } = require('./BinarySearchTree'); 4 | const TreeNode = require('./models/TreeNode'); 5 | const { 6 | defaultCompare, 7 | Compare 8 | } = require('../utils/function'); 9 | 10 | const BalanceFactor = { 11 | UNBALANCED_RIGHT: 1, 12 | SLIGHTLY_UNBALANCED_RIGHT: 2, 13 | BALANCED: 3, 14 | SLIGHTLY_UNBALANCED_LEFT: 4, 15 | UNBALANCED_LEFT: 5 16 | } 17 | 18 | 19 | class AVL extends BinarySearchTree { 20 | constructor(compareFun = defaultCompare) { 21 | super(compareFun); 22 | } 23 | 24 | getNodeHeight(node) { 25 | if (node == null) { 26 | return -1; 27 | } 28 | return Math.max(this.getNodeHeight(node.left), this.getNodeHeight(node.right)) + 1; 29 | } 30 | 31 | getBalancedFactor(node) { 32 | const heightDifference = this.getNodeHeight(node.left) - this.getNodeHeight(node.right); 33 | switch (heightDifference) { 34 | case -2: 35 | return BalanceFactor.UNBALANCED_RIGHT; 36 | break; 37 | case -1: 38 | return BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT; 39 | break; 40 | case 1: 41 | return BalanceFactor.SLIGHTLY_UNBALANCED_LEFT; 42 | break; 43 | case 2: 44 | return BalanceFactor.UNBALANCED_LEFT; 45 | break; 46 | default: 47 | return BalanceFactor.BALANCED; 48 | } 49 | } 50 | 51 | LLRotation(node) { 52 | const tmp = node.left; 53 | node.left = tmp.right; 54 | tmp.right = node; 55 | return tmp; 56 | 57 | } 58 | 59 | RRRotation(node) { 60 | const tmp = node.right; 61 | node.right = tmp.left; 62 | tmp.left = node; 63 | return tmp; 64 | } 65 | 66 | RLRotation(node) { 67 | node.right = this.LLRotation(node.right); 68 | return this.RRRotation(node); 69 | } 70 | 71 | LRRotation(node) { 72 | node.left = this.RRRotation(node.left); 73 | return this.LLRotation(node); 74 | } 75 | 76 | insert(key) { 77 | this.root = this.insertNode(this.root, key); 78 | } 79 | 80 | insertNode(node, key) { 81 | if (node == null) { 82 | return new TreeNode(key); 83 | } else if (this.compareFun(key, node.element) == Compare.LESS_THAN) { 84 | node.left = this.insertNode(node.left, key); 85 | } else if (this.compareFun(key, node.element) == Compare.BIGGER_THAN) { 86 | node.right = this.insertNode(node.right, key); 87 | } else { 88 | return node; 89 | } 90 | 91 | // Balanced Factore 92 | const balanceFactor = this.getBalancedFactor(node); 93 | if (balanceFactor == BalanceFactor.UNBALANCED_LEFT) { 94 | if (this.compareFun(key, node.left.element) == Compare.LESS_THAN) { 95 | node = this.LLRotation(node); 96 | } else { 97 | return this.LRRotation(node); 98 | } 99 | } else if (balanceFactor == BalanceFactor.UNBALANCED_RIGHT) { 100 | if (this.compareFun(key, node.left.element) == Compare.BIGGER_THAN) { 101 | node = this.RRRotation(node); 102 | } else { 103 | return this.RLRotation(node); 104 | } 105 | } 106 | 107 | } 108 | 109 | removeNode(node, element) { 110 | node = super.removeNode(node,element); 111 | if (node == null) { 112 | return null; //no need to balance 113 | } 114 | 115 | const balanceFactor = this.getBalancedFactor(node); 116 | if (balanceFactor == BalanceFactor.UNBALANCED_LEFT) { 117 | const balanceFactorLeft = this.getBalancedFactor(node.left); 118 | if (balanceFactorLeft == BalanceFactor.BALANCED || BalanceFactor.SLIGHTLY_UNBALANCED_LEFT) { 119 | node = this.LLRotation(node); 120 | } 121 | if (balanceFactorLeft == BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT) { 122 | return this.LRRotation(node); 123 | } 124 | 125 | 126 | } else if (balanceFactor == BalanceFactor.UNBALANCED_RIGHT) { 127 | const balanceFactorRight = this.getBalancedFactor(node.right); 128 | if (balanceFactorRight == BalanceFactor.BALANCED || BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT) { 129 | node = this.RRRotation(node); 130 | } 131 | if (balanceFactorRight == BalanceFactor.SLIGHTLY_UNBALANCED_LEFT) { 132 | return this.RLRotation(node); 133 | } 134 | } 135 | 136 | } 137 | 138 | } 139 | 140 | 141 | 142 | module.exports = AVL; -------------------------------------------------------------------------------- /data_structure/BinarySearchTree.js: -------------------------------------------------------------------------------- 1 | const TreeNode = require('./models/TreeNode'); 2 | const { 3 | defaultCompare, 4 | Compare 5 | } = require('../utils/function') 6 | /** 7 | * @class Binary Search Tree 8 | */ 9 | 10 | class BinarySearchTree { 11 | constructor(compareFun = defaultCompare) { 12 | this.root = null; 13 | this.compareFun = compareFun; 14 | } 15 | 16 | insert(element) { 17 | if (element == null) { 18 | return false; 19 | } 20 | if (this.root == null) { 21 | this.root = new TreeNode(element); 22 | } else { 23 | this.insertNode(element, this.root); 24 | } 25 | return true; 26 | } 27 | 28 | insertNode(element, node) { 29 | if (this.compareFun(element, node.element) == Compare.LESS_THAN) { 30 | if (node.left == null) { 31 | node.left = new TreeNode(element); 32 | } else { 33 | this.insertNode(element, node.left); 34 | } 35 | } else if (this.compareFun(element, node.element) == Compare.BIGGER_THAN) { 36 | if (node.right == null) { 37 | node.right = new TreeNode(element); 38 | } else { 39 | this.insertNode(element, node.right); 40 | } 41 | } 42 | } 43 | 44 | inOrderTraverse(callback) { 45 | this.inOrderTraverseNode(this.root, callback); 46 | } 47 | 48 | inOrderTraverseNode(node, callback) { 49 | if (node != null) { 50 | this.inOrderTraverseNode(node.left, callback); 51 | callback(node.element); 52 | this.inOrderTraverseNode(node.right, callback); 53 | } 54 | } 55 | 56 | postOrderTraverse(callback) { 57 | this.postOrderTraverseNode(this.root, callback); 58 | } 59 | postOrderTraverseNode(node, callback) { 60 | if (node != null) { 61 | this.postOrderTraverseNode(node.left, callback); 62 | this.postOrderTraverseNode(node.right, callback); 63 | callback(node.element); 64 | } 65 | } 66 | preOrderTraverse(callback) { 67 | this.preOrderTraverseNode(this.root, callback); 68 | } 69 | preOrderTraverseNode(node, callback) { 70 | if (node != null) { 71 | callback(node.element); 72 | this.preOrderTraverseNode(node.left, callback); 73 | this.preOrderTraverseNode(node.right, callback); 74 | } 75 | } 76 | 77 | min() { 78 | return this.minNode(this.root) 79 | } 80 | 81 | minNode(node) { 82 | let current = node; 83 | while (current != null && current.left != null) { 84 | current = node.left; 85 | } 86 | return current; 87 | } 88 | 89 | max() { 90 | return this.maxNode(this.root); 91 | } 92 | 93 | maxNode(node) { 94 | let current = node; 95 | while (current != null && current.right != null) { 96 | current = node.right; 97 | } 98 | return current; 99 | } 100 | 101 | search(element) { 102 | return this.searchNode(this.root, element); 103 | } 104 | 105 | searchNode(node, element) { 106 | if (node == null) { 107 | return false; 108 | } 109 | if (this.compareFun(element, node.element) == Compare.LESS_THAN) { 110 | return this.searchNode(node.left, element); 111 | } else if (this.compareFun(element, node.element) == Compare.BIGGER_THAN) { 112 | return this.searchNode(node.right, element); 113 | 114 | } else { 115 | return true; 116 | } 117 | } 118 | 119 | remove(element) { 120 | this.root = this.removeNode(this.root, element); 121 | } 122 | 123 | removeNode(node, element) { 124 | if (node == null) { 125 | return false; 126 | } 127 | 128 | if (this.compareFun(element, node.element) == Compare.LESS_THAN) { 129 | node.left = this.removeNode(node.left, element); 130 | return node; 131 | } else if (this.compareFun(element, node.element) == Compare.BIGGER_THAN) { 132 | node.right = this.removeNode(node.right, element); 133 | return node; 134 | } else { 135 | // Equal Cases 136 | /* case 1 */ 137 | if (node.left == null && node.right == null) { 138 | node = null; 139 | return node; 140 | } 141 | /* case 2 */ 142 | if (node.left == null) { 143 | node = node.right; 144 | return node; 145 | } else if (node.right == null) { 146 | node = node.left; 147 | return node; 148 | } 149 | /* case 3 */ 150 | const aux = this.minNode(node.right); 151 | node.element = aux.element; 152 | node.right = this.removeNode(node.right, aux.element); 153 | return node; 154 | } 155 | 156 | 157 | 158 | } 159 | 160 | 161 | 162 | } 163 | 164 | 165 | 166 | module.exports = { 167 | BinarySearchTree 168 | } -------------------------------------------------------------------------------- /data_structure/CircularLinkedList.js: -------------------------------------------------------------------------------- 1 | const {LinkedList} = require('./LinkedList'); 2 | const {Node} = require('./models/Node'); 3 | /** 4 | * @class Circular Linked List 5 | */ 6 | 7 | class CircularLinkedList extends LinkedList { 8 | constructor(){ 9 | super(); 10 | } 11 | 12 | push(element){ 13 | let node = new Node(element); 14 | let current = this.head; 15 | if (current == undefined) { 16 | this.head = node; 17 | node.next = this.head; 18 | } else { 19 | while(current.next != null){ 20 | current = current.next; 21 | } 22 | current.next = node; 23 | node.next = this.head; 24 | } 25 | this.count++; 26 | return this; 27 | } 28 | 29 | insert(element,index){ 30 | if (index >= 0 && index <= this.count) { 31 | const node = new Node(element); 32 | let current = this.head 33 | if (index == 0) { 34 | if (this.head == undefined) { 35 | this.head = node; 36 | node.next = this.head; 37 | }else{ 38 | node.next = current; 39 | this.head = node; 40 | } 41 | }else if (index == this.count) { 42 | const previous = this.getElementAt(index -1); 43 | previous.next = node; 44 | node.next = this.head; 45 | }else{ 46 | const previous = this.getElementAt(index -1); 47 | current = previous.next; 48 | previous.next = node; 49 | node.next = current; 50 | } 51 | this.count++; 52 | return this; 53 | } 54 | return undefined; 55 | } 56 | 57 | removeAt(index){ 58 | if (index >= 0 && index < this.count) { 59 | if (this.isEmpty()) { 60 | return undefined; 61 | } 62 | let current = this.head 63 | if (index == 0) { 64 | this.head = current.next; 65 | } else if(index == this.count-1) { 66 | const previous = this.getElementAt(index-1); 67 | current = previous.next; 68 | previous.next = this.head; 69 | }else{ 70 | const previous = this.getElementAt(index -1); 71 | current = previous.next; 72 | previous.next = current.next; 73 | } 74 | 75 | this.count --; 76 | return current.element; 77 | } 78 | return undefined; 79 | } 80 | 81 | } 82 | 83 | 84 | module.exports = { 85 | CircularLinkedList 86 | } -------------------------------------------------------------------------------- /data_structure/Dequeue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class Dequeue 3 | */ 4 | 5 | class Dequeue { 6 | constructor() { 7 | this.items = {}; 8 | this.count = 0; 9 | this.lowestCount = 0; 10 | } 11 | 12 | addFront(element) { 13 | if (this.isEmpty()) { 14 | this.addBack(element); 15 | } else if (this.lowestCount > 0) { 16 | this.lowestCount --; 17 | this.items[this.lowestCount] = element; 18 | } else { 19 | for (let index = this.count; index > 0; index--) { 20 | this.items[index] = this.items[index -1]; 21 | } 22 | this.count ++; 23 | this.items[0] = element; 24 | } 25 | } 26 | addBack(element) { 27 | this.items[this.count] = element; 28 | this.count++; 29 | } 30 | removeFront() { 31 | if (this.isEmpty()) { 32 | return undefined; 33 | } 34 | 35 | let result = this.items[this.lowestCount]; 36 | delete this.items[this.lowestCount]; 37 | this.lowestCount++; 38 | return result; 39 | 40 | } 41 | removeBack() { 42 | if (this.isEmpty()) { 43 | return undefined; 44 | } 45 | let result = this.items[this.count - 1]; 46 | delete this.items[this.count - 1]; 47 | this.count--; 48 | return result; 49 | } 50 | 51 | peekFront(){ 52 | if (this.isEmpty()) { 53 | return undefined; 54 | } 55 | return this.items[this.lowestCount]; 56 | } 57 | 58 | peekBack(){ 59 | if (this.isEmpty()) { 60 | return undefined; 61 | } 62 | return this.items[this.count -1]; 63 | } 64 | 65 | 66 | 67 | isEmpty() { 68 | return this.count - this.lowestCount == 0; 69 | } 70 | 71 | size() { 72 | return this.count - this.lowestCount; 73 | } 74 | 75 | clear() { 76 | this.items = {}; 77 | this.count = 0; 78 | this.lowestCount = 0; 79 | } 80 | 81 | toString() { 82 | if (this.isEmpty()) { 83 | return ""; 84 | } 85 | let string = `${this.items[this.lowestCount]}`; 86 | for (let index = this.lowestCount + 1; index < this.count; index++) { 87 | string = `${string},${this.items[index]}`; 88 | } 89 | return string; 90 | } 91 | 92 | } 93 | 94 | 95 | module.exports = { 96 | Dequeue 97 | }; -------------------------------------------------------------------------------- /data_structure/Dictionary.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class Dictionary Data Structure or also know as Map 3 | */ 4 | 5 | const { 6 | KeyValue 7 | } = require('./models/KeyValue'); 8 | const { 9 | toStringFunc 10 | } = require('../utils/function'); 11 | 12 | class Dictionary { 13 | constructor(toStrFn = toStringFunc) { 14 | this.table = {}; 15 | this.toStrFn = toStrFn; 16 | } 17 | 18 | set(key, value) { 19 | if (key != null & value != null) { 20 | const stringKey = this.toStrFn(key); 21 | this.table[stringKey] = new KeyValue(key, value); 22 | return true; 23 | } 24 | return false; 25 | } 26 | 27 | hasKey(key) { 28 | return this.table[this.toStrFn(key)] !== null; 29 | } 30 | 31 | 32 | get(key) { 33 | const keyValuesPair = this.table[this.toStrFn(key)]; 34 | return keyValuesPair != null ? keyValuesPair.value : null; 35 | 36 | } 37 | 38 | keys() { 39 | return this.keyValues().map(element => element.key); 40 | } 41 | 42 | values() { 43 | return this.keyValues().map(element => element.value); 44 | } 45 | 46 | keyValues() { 47 | const keyValuePairs = []; 48 | for (const key in this.table) { 49 | if (this.table.hasOwnProperty(key)) { 50 | keyValuePairs.push(this.table[key]) 51 | } 52 | } 53 | return keyValuePairs; 54 | } 55 | 56 | remove(key) { 57 | if (this.hasKey(key)) { 58 | delete this.table[this.toStrFn(key)]; 59 | return true; 60 | } 61 | return false; 62 | } 63 | 64 | isEmpty() { 65 | return Object.keys(this.table).length == 0; 66 | } 67 | size() { 68 | return Object.keys(this.table).length; 69 | } 70 | 71 | toString() { 72 | if (this.isEmpty()) { 73 | return ""; 74 | } 75 | let keyValuePairs = this.keyValues(); 76 | let string = `${keyValuePairs[0].toString()}` 77 | for (let index = 1; index < keyValuePairs.length; index++) { 78 | string = `${string}, ${keyValuePairs[index].toString()}` 79 | } 80 | return string; 81 | } 82 | 83 | forEach(callback) { 84 | let keyValuePairs = this.keyValues(); 85 | for (let index = 0; index < keyValuePairs.length; index++) { 86 | const result = callback(keyValuePairs[index].key, keyValuePairs[index].value); 87 | if (result == false) { 88 | break; 89 | } 90 | 91 | } 92 | } 93 | } 94 | 95 | 96 | 97 | module.exports = { 98 | Dictionary 99 | } -------------------------------------------------------------------------------- /data_structure/DoubleLinkedList.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class Double Linked List 3 | */ 4 | 5 | const { 6 | LinkedList 7 | } = require('./LinkedList'); 8 | const { 9 | DoublyNode 10 | } = require('./models/DoublyNode'); 11 | 12 | class DoubleLinkedList extends LinkedList { 13 | constructor(func) { 14 | super(func); 15 | this.tail = undefined; 16 | } 17 | 18 | getTail(){ 19 | if (this.isEmpty()) { 20 | return undefined; 21 | } 22 | return this.tail.element; 23 | } 24 | 25 | push(element) { 26 | let node = new DoublyNode(element); 27 | if (this.head == undefined) { 28 | this.head = node; 29 | this.tail = node; 30 | } else { 31 | let current = this.tail; 32 | current.next = node; 33 | node.previous = current; 34 | this.tail = node; 35 | 36 | } 37 | this.count++; 38 | } 39 | 40 | insert(element, index) { 41 | if (index >= 0 && index <= this.count) { 42 | 43 | let node = new DoublyNode(element); 44 | let current = this.head; 45 | if (index == 0) { 46 | if (this.head == undefined) { 47 | this.head = node; 48 | this.tail = node; 49 | } else { 50 | current.previous = node; 51 | node.next = current; 52 | this.head = node; 53 | } 54 | } else if (index == this.count) { 55 | current = this.tail; 56 | current.next = node; 57 | node.previous = current; 58 | this.tail = node; 59 | } else { 60 | let previous = this.getElementAt(index - 1); 61 | current = previous.next; 62 | previous.next = node; 63 | node.next = current; 64 | node.previous = previous; 65 | current.previous = node; 66 | } 67 | this.count++; 68 | } 69 | } 70 | 71 | removeAt(index) { 72 | if (this.isEmpty()) { 73 | return undefined; 74 | } 75 | if (index >= 0 && index < this.count) { 76 | let current = this.head; 77 | if (index == 0) { 78 | this.head = current.next; 79 | if (this.count == 1) { 80 | this.tail = undefined; 81 | }else{ 82 | this.head.previous = undefined; 83 | } 84 | }else if (index == this.count-1){ 85 | current = this.tail; 86 | this.tail = current.previous; 87 | this.tail.next = undefined; 88 | }else{ 89 | current = this.getElementAt(index); 90 | const previous = current.previous; 91 | // link previous with current's next 92 | previous.next = current.next; 93 | current.next.previous = previous; 94 | } 95 | this.count --; 96 | return current.element; 97 | } 98 | } 99 | 100 | } 101 | 102 | module.exports = { 103 | DoubleLinkedList 104 | } -------------------------------------------------------------------------------- /data_structure/Graph.js: -------------------------------------------------------------------------------- 1 | const { 2 | Dictionary 3 | } = require('./Dictionary'); 4 | 5 | class Graph { 6 | constructor(isDirected = false) { 7 | this.isDirected = isDirected; 8 | this.vertices = []; 9 | this.adjList = new Dictionary(); 10 | } 11 | 12 | /* Add Vertex */ 13 | addVertex(vertex) { 14 | if (!this.adjList.get(vertex)) { 15 | this.vertices.push(vertex); 16 | this.adjList.set(vertex, []); 17 | } 18 | } 19 | 20 | /* Add Edge */ 21 | addEdge(vertexX, vertexY) { 22 | if (!this.adjList.get(vertexX)) { 23 | this.addVertex(vertexX) 24 | } 25 | if (!this.adjList.get(vertexY)) { 26 | this.addVertex(vertexY) 27 | } 28 | this.adjList.get(vertexX).push(vertexY); 29 | if (!this.isDirected) { 30 | this.adjList.get(vertexY).push(vertexX); 31 | } 32 | } 33 | 34 | getVertices() { 35 | return this.vertices; 36 | } 37 | 38 | getEdges() { 39 | return this.adjList; 40 | } 41 | 42 | toString() { 43 | let str = ""; 44 | for (let index = 0; index < this.vertices.length; index++) { 45 | str += `${this.vertices[index]} -> ${this.adjList.get(this.vertices[index]).join(" ")} \n`; 46 | } 47 | return str; 48 | } 49 | 50 | } 51 | 52 | module.exports = { 53 | Graph 54 | } -------------------------------------------------------------------------------- /data_structure/HashTable.js: -------------------------------------------------------------------------------- 1 | const { 2 | KeyValue 3 | } = require('./models/KeyValue'); 4 | const { 5 | toStringFunc 6 | } = require('../utils/function'); 7 | 8 | class HashTable { 9 | constructor() { 10 | this.table = {}; 11 | } 12 | 13 | _loseloseHashCode(key) { 14 | if (typeof key == "number") { 15 | return key; 16 | } 17 | const keyString = toStringFunc(key); 18 | let code = 0; 19 | for (let index = 0; keyString < key.length; index++) { 20 | code += keyString.charCodeAt(index); 21 | } 22 | return code % 37; 23 | } 24 | 25 | 26 | getHashCode(key) { 27 | return this._loseloseHashCode(key); 28 | } 29 | 30 | 31 | put(key, value) { 32 | if (key != null && value != null) { 33 | const keyHash = this.getHashCode(key); 34 | this.table[keyHash] = new KeyValue(key, value); 35 | return true; 36 | } 37 | return false; 38 | } 39 | 40 | remove(key) { 41 | const keyHash = this.getHashCode(key); 42 | if (this.table[keyHash]) { 43 | const value = this.table[keyHash]; 44 | delete this.table[keyHash]; 45 | return value; 46 | } 47 | return undefined; 48 | } 49 | 50 | get(key) { 51 | const keyHash = this.getHashCode(key); 52 | return this.table[keyHash] != null ? this.table[keyHash].value : undefined; 53 | } 54 | 55 | djb2HashCode(key) { 56 | const tableKey = toStringFunc(key); // {1} 57 | let hash = 5381; // {2} 58 | for (let i = 0; i < tableKey.length; i++) { // {3} 59 | hash = (hash * 33) + tableKey.charCodeAt(i); // {4} 60 | } 61 | return hash % 1013; // {5} 62 | } 63 | 64 | isEmpty() { 65 | return Object.keys(this.table).length == 0; 66 | } 67 | size() { 68 | return Object.keys(this.table).length; 69 | } 70 | 71 | keyValues() { 72 | const keyValuePairs = []; 73 | for (const key in this.table) { 74 | if (this.table.hasOwnProperty(key)) { 75 | keyValuePairs.push(this.table[key]) 76 | } 77 | } 78 | return keyValuePairs; 79 | } 80 | 81 | toString() { 82 | if (this.isEmpty()) { 83 | return ""; 84 | } 85 | let keyValuePairs = this.keyValues(); 86 | let string = `${keyValuePairs[0].toString()}` 87 | for (let index = 1; index < keyValuePairs.length; index++) { 88 | string = `${string}, ${keyValuePairs[index].toString()}` 89 | } 90 | return string; 91 | } 92 | 93 | forEach(callback) { 94 | let keyValuePairs = this.keyValues(); 95 | for (let index = 0; index < keyValuePairs.length; index++) { 96 | const result = callback(keyValuePairs[index].key, keyValuePairs[index].value); 97 | if (result == false) { 98 | break; 99 | } 100 | 101 | } 102 | } 103 | 104 | } 105 | 106 | 107 | module.exports = { 108 | HashTable 109 | } 110 | -------------------------------------------------------------------------------- /data_structure/HashTableLinearProbing.js: -------------------------------------------------------------------------------- 1 | const { 2 | HashTable 3 | } = require('./HashTable'); 4 | const { 5 | KeyValue 6 | } = require('./models/KeyValue'); 7 | 8 | 9 | 10 | class HashTableLinearProbing extends HashTable { 11 | constructor() { 12 | super(); 13 | } 14 | 15 | put(key, value) { 16 | if (key != null && value != null) { 17 | const hashKey = this.getHashCode(key); 18 | if (this.table[hashKey] == null) { 19 | this.table[hashKey] = new KeyValue(key, value); 20 | } else { 21 | 22 | let position = hashKey + 1; 23 | while (this.table[position] != null) { 24 | position++; 25 | } 26 | this.table[position] = new KeyValue(key, value); 27 | } 28 | return true; 29 | } 30 | return false; 31 | } 32 | 33 | get(key) { 34 | const hashKey = this.getHashCode(key); 35 | if (this.table[hashKey] != null) { 36 | if (this.table[hashKey].key == key) { 37 | return this.table[hashKey].value; 38 | } 39 | 40 | let position = hashKey + 1; 41 | while (this.table[position] != null && this.table[position].key != key) { 42 | position++; 43 | } 44 | 45 | if (this.table[position] && this.table[position].key == key) { 46 | return this.table[position].value; 47 | } 48 | } 49 | return undefined; 50 | } 51 | 52 | remove(key) { 53 | const hashKey = this.getHashCode(key); 54 | if (this.table[hashKey] != null) { 55 | if (this.table[hashKey].key == key) { 56 | delete this.table[hashKey]; 57 | this.verifyRemoveSideEffect(key, hashKey); 58 | return true; 59 | } 60 | 61 | let position = hashKey + 1; 62 | while (this.table[position] != null && this.table[position].key != key) { 63 | position++; 64 | } 65 | 66 | if (this.table[position] && this.table[position].key == key) { 67 | delete this.table[position]; 68 | this.verifyRemoveSideEffect(key, position); 69 | return true; 70 | } 71 | } 72 | return false; 73 | 74 | } 75 | 76 | 77 | verifyRemoveSideEffect(key, removePosition) { 78 | const hashKey = this.getHashCode(key); 79 | let position = removePosition +1; 80 | while(this.table[position] != null){ 81 | const hashKeyPosition = this.getHashCode(this.table[position].key); 82 | if (hashKeyPosition <= hashKey || hashKeyPosition <= removePosition ) { 83 | this.table[removePosition] = this.table[position]; 84 | delete this.table[position]; 85 | removePosition = position; 86 | } 87 | position ++; 88 | } 89 | } 90 | } 91 | 92 | 93 | module.exports = { 94 | HashTableLinearProbing 95 | }; -------------------------------------------------------------------------------- /data_structure/HashTableSeparateChaining.js: -------------------------------------------------------------------------------- 1 | const { 2 | HashTable 3 | } = require('./HashTable'); 4 | const { 5 | LinkedList 6 | } = require('./LinkedList'); 7 | const { 8 | KeyValue 9 | } = require('./models/KeyValue'); 10 | 11 | class HashTableSeparateChaining extends HashTable { 12 | constructor() { 13 | super(); 14 | } 15 | 16 | put(key, value) { 17 | if (key != null && value != null) { 18 | 19 | const hashKey = this.getHashCode(key); 20 | if (this.table[hashKey] == null) { 21 | this.table[hashKey] = new LinkedList(); 22 | } 23 | this.table[hashKey].push(new KeyValue(key, value)); 24 | return true; 25 | } 26 | 27 | return false; 28 | } 29 | 30 | get(key) { 31 | const hashKey = this.getHashCode(key); 32 | const linkedList = this.table[hashKey]; 33 | if (linkedList.size() > 0 && !linkedList.isEmpty()) { 34 | let current = linkedList.getHead(); 35 | while (current.next != null) { 36 | if (current.element.key == key) { 37 | return current.element.value; 38 | } 39 | current = current.next; 40 | } 41 | } 42 | return undefined; 43 | } 44 | remove(key) { 45 | const hashKey = this.getHashCode(key); 46 | const linkedList = this.table[hashKey]; 47 | if (linkedList.size() > 0 && !linkedList.isEmpty()) { 48 | let current = linkedList.getHead(); 49 | while (current.next != null) { 50 | if (current.element.key == key) { 51 | linkedList.remove(current.element); 52 | if (linkedList.isEmpty()) { 53 | delete this.table[hashKey]; 54 | } 55 | return current.element; 56 | } 57 | current = current.next; 58 | } 59 | } 60 | return undefined; 61 | } 62 | 63 | } 64 | 65 | 66 | 67 | module.exports = { 68 | HashTableSeparateChaining 69 | } -------------------------------------------------------------------------------- /data_structure/LinkedList.js: -------------------------------------------------------------------------------- 1 | const { 2 | Node, defaultEq 3 | } = require("./models/Node"); 4 | 5 | /** 6 | * @class Linked List 7 | */ 8 | class LinkedList { 9 | constructor(equalFunc = defaultEq) { 10 | this.count = 0; 11 | this.head = undefined; 12 | this.equalFunc = equalFunc; 13 | } 14 | 15 | getHead(){ 16 | if (this.isEmpty()) { 17 | return undefined; 18 | } 19 | return this.head.element; 20 | } 21 | 22 | push(element) { 23 | const node = new Node(element); 24 | let current = this.head; 25 | if (this.head == undefined) { 26 | this.head = node; 27 | }else{ 28 | while (current.next != null) { 29 | current = current.next 30 | } 31 | current.next = node; 32 | } 33 | this.count++; 34 | return; 35 | } 36 | 37 | insert(element, postion) { 38 | if (postion >= 0 && postion <= this.count) { 39 | const node = new Node(element); 40 | let current = this.head; 41 | if (postion == 0) { 42 | if (this.head == undefined) { 43 | this.head = node; 44 | } 45 | this.head = node; 46 | node.next = current; 47 | } else { 48 | let previous = this.getElementAt(postion - 1); 49 | current = previous.next; 50 | node.next = current; 51 | previous.next = node; 52 | } 53 | } 54 | this.count++; 55 | } 56 | 57 | getElementAt(index) { 58 | let node = this.head; 59 | if (index >= 0 && index < this.count) { 60 | for (let i = 0; i < index; i++) { 61 | node = node.next; 62 | } 63 | return node; 64 | } 65 | return undefined; 66 | } 67 | 68 | indexOf(element) { 69 | let current = this.head; 70 | for (let index = 0; index < this.count && current != null; index++) { 71 | if (this.equalFunc(current.element,element)) { 72 | return index; 73 | } 74 | current = current.next; 75 | } 76 | return -1; 77 | } 78 | 79 | remove(element) { 80 | if (this.isEmpty()) { 81 | return undefined; 82 | } 83 | let index = this.indexOf(element); 84 | if (index != -1) { 85 | this.removeAt(index); 86 | } 87 | return undefined; 88 | } 89 | 90 | removeAt(index) { 91 | if (this.isEmpty()) { 92 | return undefined; 93 | } 94 | if (index >= 0 && index < this.count) { 95 | 96 | let current = this.head 97 | if (index == 0) { 98 | this.head = current.next; 99 | } else { 100 | let previous = this.getElementAt(index - 1); 101 | current = previous.next; 102 | previous.next = current.next; 103 | } 104 | this.count--; 105 | return current.element; 106 | } 107 | return undefined; 108 | } 109 | 110 | isEmpty() { 111 | return this.count == 0; 112 | } 113 | 114 | size() { 115 | return this.count; 116 | } 117 | 118 | toString() { 119 | if (this.isEmpty()) { 120 | return "" 121 | } 122 | let string = `${this.head.element}`; 123 | let current = this.head.next; 124 | for (let index = 1; index < this.count && current != null; index++) { 125 | string = `${string}, ${current.element}` 126 | current = current.next; 127 | } 128 | return string; 129 | } 130 | 131 | toArray(){ 132 | let elements = []; 133 | let current = this.head; 134 | while(this.count && current != null){ 135 | elements.push(current.element); 136 | current = current.next; 137 | } 138 | return elements; 139 | } 140 | 141 | } 142 | 143 | 144 | module.exports = { 145 | LinkedList 146 | } -------------------------------------------------------------------------------- /data_structure/MaxHeap.js: -------------------------------------------------------------------------------- 1 | const { 2 | defaultCompare, 3 | Compare 4 | } = require('../utils/function'); 5 | 6 | const {MinHeap} = require('./MinHeap'); 7 | 8 | const reverseCompare = (compareFunc) => (a, b) => compareFunc(b, a) 9 | 10 | class MaxHeap extends MinHeap { 11 | constructor(compareFunc = defaultCompare){ 12 | super(compareFunc); 13 | this.compareFunc = reverseCompare(compareFunc); 14 | } 15 | } 16 | 17 | 18 | module.exports = { 19 | MaxHeap 20 | } -------------------------------------------------------------------------------- /data_structure/MinHeap.js: -------------------------------------------------------------------------------- 1 | const { 2 | defaultCompare, 3 | Compare 4 | } = require('../utils/function'); 5 | 6 | 7 | class MinHeap { 8 | constructor(compareFunc = defaultCompare) { 9 | this.heap = []; 10 | this.compareFunc = compareFunc; 11 | } 12 | 13 | getParentIndex(index) { 14 | if (index == 0) { 15 | return undefined; 16 | } 17 | return Math.floor((index - 1) / 2); 18 | } 19 | getLeftChildIndex(index) { 20 | return (index * 2) + 1; 21 | } 22 | getRightChildIndex(index) { 23 | return (index * 2) + 2; 24 | } 25 | 26 | 27 | insert(element) { 28 | if (element != null) { 29 | this.heap.push(element); 30 | this.siftUp(this.heap.length - 1); 31 | return true; 32 | } 33 | return false; 34 | 35 | } 36 | 37 | siftUp(index) { 38 | let parent = this.getParentIndex(index); 39 | while (index > 0 && this.compareFunc(this.heap[parent], this.heap[index]) == Compare.BIGGER_THAN ) { 40 | this.swap(this.heap,parent,index); 41 | index = parent; 42 | parent = this.getParentIndex(index); 43 | } 44 | } 45 | 46 | swap(array, a, b) { 47 | const tmp = array[a]; 48 | array[a] = array[b]; 49 | array[b] = tmp; 50 | } 51 | 52 | 53 | //Return the Min Values in Case of MinHeap 54 | //Return the Max Values in Case of MaxHeap 55 | extract() { 56 | if (this.isEmpty()) { 57 | return undefined; 58 | } 59 | if (this.size() == 1) { 60 | return this.heap.shift(); 61 | } 62 | 63 | const removeElement = this.heap.shift(); 64 | this.siftDown(0); 65 | return removeElement; 66 | } 67 | 68 | 69 | //Heapify 70 | siftDown(index){ 71 | let element = index; 72 | let left = this.getLeftChildIndex(index); 73 | let right = this.getRightChildIndex(index); 74 | const size = this.size(); 75 | if (left < size && this.compareFunc(this.heap[element], this.heap[left]) > Compare.BIGGER_THAN) { 76 | element = left; 77 | } 78 | if (right < size && this.compareFunc(this.heap[element], this.heap[right]) > Compare.BIGGER_THAN) { 79 | element = right; 80 | } 81 | 82 | if (index !== element) { 83 | this.swap(this.heap,index,element); 84 | this.siftDown(element); 85 | } 86 | } 87 | 88 | findMinimum() { 89 | if (!this.isEmpty()) { 90 | return this.heap[0]; 91 | } 92 | return undefined; 93 | } 94 | 95 | isEmpty() { 96 | return this.heap.length == 0; 97 | } 98 | 99 | size() { 100 | return this.heap.length; 101 | } 102 | 103 | } 104 | 105 | 106 | module.exports = { 107 | MinHeap 108 | } -------------------------------------------------------------------------------- /data_structure/Queue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class Queue implement using Object 3 | * FIFO (first in - first out) 4 | */ 5 | 6 | class Queue { 7 | constructor(){ 8 | this.count = 0; 9 | this.lowestCount = 0; 10 | this.items = {}; 11 | } 12 | 13 | equeue(element){ 14 | this.items[this.count] = element; 15 | this.count ++; 16 | } 17 | 18 | /* remove the element which was insert first */ 19 | dequeue(){ 20 | if (this.isEmpty()) { 21 | return undefined; 22 | } 23 | let result = this.items[this.lowestCount]; 24 | delete this.items[this.lowestCount]; 25 | this.lowestCount ++; 26 | return result; 27 | 28 | } 29 | 30 | isEmpty(){ 31 | return this.count - this.lowestCount == 0; 32 | } 33 | 34 | size(){ 35 | return this.count - this.lowestCount; 36 | } 37 | 38 | peek(){ 39 | if (this.isEmpty()) { 40 | return undefined; 41 | } 42 | return this.items[this.lowestCount]; 43 | 44 | } 45 | clear(){ 46 | this.items = {} 47 | this.count = 0; 48 | this.lowestCount = 0; 49 | return this.items; 50 | } 51 | 52 | toString(){ 53 | if (this.isEmpty()) { 54 | return ""; 55 | } 56 | let string = `${this.items[this.lowestCount]}`; 57 | for (let index = this.lowestCount+1; index < this.count; index++) { 58 | string = `${string},${this.items[index]}`; 59 | } 60 | return string; 61 | } 62 | 63 | } 64 | 65 | 66 | module.exports = {Queue}; -------------------------------------------------------------------------------- /data_structure/RedBlackTree.js: -------------------------------------------------------------------------------- 1 | const { 2 | Colors, 3 | RedBlackNode 4 | } = require('./models/RedBlackNode'); 5 | const { 6 | BinarySearchTree 7 | } = require('./BinarySearchTree'); 8 | const { 9 | defaultCompare, 10 | Compare 11 | } = require('../utils/function') 12 | class RedBlackTree extends BinarySearchTree { 13 | constructor(compareFunc = defaultCompare) { 14 | super(compareFunc); 15 | } 16 | 17 | insert(key) { 18 | if (this.root == null) { 19 | this.root = new RedBlackNode(key); 20 | // Root Node Must be Black 21 | this.root.Colors = Colors.BLACK 22 | } else { 23 | const newNode = this.insertNode(this.root, key); 24 | this.fixTreeProperties(newNode); 25 | } 26 | } 27 | 28 | insertNode(node, key) { 29 | if (this.compareFun(key, node.element) == Compare.LESS_THAN) { 30 | if (node.left == null) { 31 | node.left = new RedBlackNode(key); 32 | node.left.parent = node 33 | } else { 34 | return this.insertNode(node.left, key); 35 | } 36 | } else if (this.compareFun(key, node.element) == Compare.BIGGER_THAN) { 37 | if (node.right == null) { 38 | node.right = new RedBlackNode(key); 39 | node.right.parent = node; 40 | } else { 41 | return this.insertNode(node.right, key); 42 | } 43 | } 44 | } 45 | // Recoloring or Rotating 46 | fixTreeProperties(node) { 47 | while (node && node.parent && node.parent.isRed() && node.parent.color != Colors.BLACK) { 48 | let parent = node.parent; 49 | let grandParent = parent.parent; 50 | // Case A : parent is left 51 | if (grandParent && grandParent.left == parent) { 52 | // Case 1A : Recoloring 53 | let uncle = grandParent.right; 54 | if (uncle && uncle.isRed()) { 55 | // If the node is red then its descendent will be BLACK 56 | grandParent.color = Colors.RED; 57 | parent.color = Colors.BLACK; 58 | uncle.color = Colors.BLACK; 59 | node = grandParent; 60 | } 61 | 62 | // Case 2A : parent is rigth LR Rotation 63 | if (node == parent.right) { 64 | this.LRRotation(parent); 65 | node = parent; 66 | parent = node.parent; 67 | } 68 | // Case 3A : parent is left LL Rotation 69 | this.LLRotation(grandParent); 70 | parent.color = Colors.BLACK; 71 | grandParent.color = Colors.RED; 72 | node = parent; 73 | 74 | } else { 75 | let uncle = grandParent.left; 76 | if (uncle && uncle.isRed()) { 77 | // If the node is red then its descendent will be BLACK 78 | grandParent.color = Colors.RED; 79 | parent.color = Colors.BLACK; 80 | uncle.color = Colors.BLACK; 81 | node = grandParent; 82 | } 83 | 84 | // Case 2A : parent is left RL Rotation 85 | if (node == parent.left) { 86 | this.RLRotation(parent); 87 | node = parent; 88 | parent = node.parent; 89 | } 90 | // Case 3A : parent is left RR Rotation 91 | this.RRRotation(grandParent); 92 | parent.color = Colors.BLACK; 93 | grandParent.color = Colors.RED; 94 | node = parent; 95 | 96 | } 97 | 98 | 99 | } 100 | this.root.color = Colors.BLACK; 101 | } 102 | 103 | LLRotation(node) { 104 | const tmp = node.left; 105 | node.right = tmp.left; 106 | if (tmp.right && tmp.right.element) { 107 | tmp.right.parent = node; 108 | } 109 | tmp.parent = node.parent; 110 | if (!node.parent) { 111 | this.root = tmp; 112 | } else { 113 | 114 | if (node === node.parent.left) { 115 | node.parent.left = tmp; 116 | } else { 117 | node.parent.right = tmp; 118 | } 119 | 120 | 121 | } 122 | tmp.right = node; 123 | node.parent = tmp; 124 | 125 | } 126 | RRRotation(node) { 127 | const tmp = node.right; 128 | node.left = tmp.right; 129 | if (tmp.left && tmp.left.element) { 130 | tmp.left.parent = node; 131 | } 132 | tmp.parent = node.parent; 133 | if (!node.parent) { 134 | this.root = tmp; 135 | } else { 136 | 137 | if (node === node.parent.left) { 138 | node.parent.left = tmp; 139 | } else { 140 | node.parent.right = tmp; 141 | } 142 | 143 | 144 | } 145 | tmp.left = node; 146 | node.parent = tmp; 147 | } 148 | LRRotation(node) { 149 | node.left = this.RRRotation(node.left); 150 | return this.RRRotation(node); 151 | } 152 | RLRotation(node) { 153 | node.right = this.LLRotation(node.right); 154 | return this.LLRotation(node); 155 | } 156 | 157 | removeNode(node, element) { 158 | const newNode = super.removeNode(node, element); 159 | if (node == null) { 160 | return null; 161 | } 162 | this.fixTreeProperties(newNode); 163 | return newNode; 164 | } 165 | 166 | } 167 | 168 | 169 | module.exports = { 170 | RedBlackTree 171 | } -------------------------------------------------------------------------------- /data_structure/Set.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class Set Implementation 3 | */ 4 | 5 | class Set { 6 | constructor() { 7 | this.items = {}; 8 | } 9 | 10 | has(element) { 11 | /* return element in this.items; */ 12 | return Object.prototype.hasOwnProperty.call(this.items, element); 13 | } 14 | 15 | add(element) { 16 | if (!this.has(element)) { 17 | this.items[element] = element; 18 | return true; 19 | } 20 | return false; 21 | } 22 | 23 | delete(element) { 24 | if (this.has(element)) { 25 | delete this.items[element]; 26 | return true; 27 | } 28 | return false; 29 | } 30 | 31 | clear() { 32 | this.items = {}; 33 | } 34 | 35 | isEmpty() { 36 | return Object.keys(this.items).length == 0; 37 | } 38 | 39 | size() { 40 | return Object.keys(this.items).length; 41 | } 42 | 43 | 44 | elements(){ 45 | /* return Object.elements(this.items); */ 46 | let elements = []; 47 | for (const key in this.items) { 48 | if (this.items.hasOwnProperty(key)) { 49 | elements.push(key); 50 | } 51 | } 52 | return elements; 53 | } 54 | 55 | union(otherSet){ 56 | if (!(otherSet instanceof Set)) { 57 | throw new Error("Must be Instance Of Set"); 58 | } 59 | const unionSet = new Set(); 60 | this.elements().forEach(element => { 61 | unionSet.add(element); 62 | }); 63 | otherSet.elements().forEach(element => { 64 | unionSet.add(element); 65 | }); 66 | 67 | return unionSet; 68 | 69 | } 70 | intersection(otherSet){ 71 | if (!(otherSet instanceof Set)) { 72 | throw new Error("Must be Instance Of Set"); 73 | } 74 | const intersectionSet = new Set(); 75 | this.elements().forEach(element => { 76 | if (otherSet.has(element)) { 77 | intersectionSet.add(element); 78 | } 79 | }); 80 | 81 | return intersectionSet; 82 | } 83 | difference(otherSet){ 84 | if (!(otherSet instanceof Set)) { 85 | throw new Error("Must be Instance Of Set"); 86 | } 87 | const differenceSet = new Set(); 88 | this.elements().forEach(element => { 89 | if (!otherSet.has(element)) { 90 | differenceSet.add(element); 91 | } 92 | }); 93 | return differenceSet; 94 | } 95 | isSubset(otherSet){ 96 | if (!(otherSet instanceof Set)) { 97 | throw new Error("Must be Instance Of Set"); 98 | } 99 | if (!(otherSet.size() > this.size())) { 100 | return false; 101 | } 102 | let isSubset = true; 103 | this.elements().every(element => { 104 | if (!otherSet.has(element)) { 105 | isSubset = false; 106 | return; 107 | } 108 | }); 109 | 110 | return isSubset; 111 | 112 | } 113 | 114 | toString(){ 115 | return this.elements().toString(); 116 | } 117 | } 118 | 119 | 120 | module.exports = { 121 | Set 122 | } -------------------------------------------------------------------------------- /data_structure/SortedLinkedList.js: -------------------------------------------------------------------------------- 1 | 2 | const {LinkedList} = require('./LinkedList'); 3 | const {Node} = require('./Node'); 4 | const {defaultCompare,Compare} = require('../utils/function') 5 | /** 6 | * @class SortedLinkedList 7 | */ 8 | class SortedLinkedList extends LinkedList { 9 | constructor(func, CompareFun = defaultCompare){ 10 | super(func); 11 | this.CompareFun = CompareFun; 12 | } 13 | 14 | insert(element, index =0){ 15 | if (this.isEmpty()) { 16 | return super.insert(element,index) 17 | }else{ 18 | const pos = getNextSortIndex(element); 19 | return super.insert(element,pos); 20 | } 21 | } 22 | 23 | getNextSortIndex(element){ 24 | let current = this.head; 25 | let i = 0; 26 | for (; i < current.next != null ; i++) { 27 | if (this.CompareFun(element,current.element) == Compare.LESS_THAN) { 28 | return i; 29 | } 30 | current = current.next; 31 | } 32 | return i; 33 | } 34 | } -------------------------------------------------------------------------------- /data_structure/Stack.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class Stack implement using Array 3 | */ 4 | class Stack { 5 | constructor() { 6 | this.items = []; 7 | } 8 | 9 | push(element) { 10 | this.items.push(element); 11 | } 12 | 13 | pop() { 14 | return this.items.pop(); 15 | } 16 | 17 | isEmpty() { 18 | return this.items.length == 0; 19 | } 20 | 21 | peek() { 22 | return this.items[this.items.length - 1]; 23 | } 24 | 25 | size() { 26 | return this.items.length; 27 | } 28 | 29 | clear(){ 30 | this.items = []; 31 | } 32 | 33 | toString(){ 34 | return this.items.toString(); 35 | } 36 | 37 | 38 | } 39 | 40 | /** 41 | * @class Stack implement using Object 42 | */ 43 | class StackObject { 44 | constructor() { 45 | this.count = 0; 46 | this.items = {}; 47 | } 48 | 49 | push(element) { 50 | this.items[this.count] = element; 51 | this.count++; 52 | } 53 | 54 | pop() { 55 | if (this.isEmpty()) { 56 | return undefined; 57 | } 58 | let result = this.items[this.count-1]; 59 | this.count --; 60 | delete this.items[this.count]; 61 | 62 | return result; 63 | } 64 | 65 | isEmpty() { 66 | return this.count == 0; 67 | } 68 | 69 | peek() { 70 | return this.items[this.count-1]; 71 | } 72 | 73 | size() { 74 | return this.count; 75 | } 76 | 77 | clear() { 78 | /* while (!this.isEmpty()) { 79 | this.pop() 80 | } */ 81 | this.items = {}; 82 | this.count = 0; 83 | return this.items; 84 | } 85 | 86 | toString(){ 87 | let string = `${this.items[0]}`; 88 | for (let index = 1; index < this.count; index++) { 89 | string = `${string},${this.items[index]}` 90 | } 91 | return string; 92 | } 93 | 94 | } 95 | 96 | 97 | module.exports = {Stack, StackObject}; -------------------------------------------------------------------------------- /data_structure/models/DoublyNode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class Double Linked Node 3 | */ 4 | 5 | const { 6 | Node 7 | } = require('./Node'); 8 | 9 | 10 | class DoublyNode extends Node { 11 | constructor(element, next, previous) { 12 | super(element, next); 13 | this.previous = previous; 14 | } 15 | } 16 | 17 | module.exports = { 18 | DoublyNode 19 | } -------------------------------------------------------------------------------- /data_structure/models/KeyValue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Key : Value 3 | */ 4 | 5 | class KeyValue{ 6 | constructor(key, value){ 7 | this.key = key; 8 | this.value = value; 9 | } 10 | toString(){ 11 | return `[#${this.key} , ${this.value}]` 12 | } 13 | } 14 | 15 | 16 | module.exports = { 17 | KeyValue 18 | } -------------------------------------------------------------------------------- /data_structure/models/Node.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Linked List Node 3 | */ 4 | 5 | 6 | class Node { 7 | constructor(element){ 8 | this.element = element; 9 | this.next = null; 10 | } 11 | } 12 | 13 | 14 | const defaultEq = (a,b) => { 15 | return a == b; 16 | } 17 | 18 | module.exports = { Node, defaultEq} -------------------------------------------------------------------------------- /data_structure/models/RedBlackNode.js: -------------------------------------------------------------------------------- 1 | const TreeNode = require('./TreeNode') 2 | 3 | const Colors = { 4 | RED : 0, 5 | BLACK :1 6 | } 7 | 8 | 9 | class RedBlackNode extends TreeNode { 10 | constructor(element){ 11 | super(element); 12 | this.color = Colors.RED; 13 | this.parent = null; 14 | } 15 | 16 | isRed(){ 17 | this.color == Colors.RED; 18 | } 19 | } 20 | 21 | 22 | module.exports = { 23 | Colors, 24 | RedBlackNode 25 | } -------------------------------------------------------------------------------- /data_structure/models/TreeNode.js: -------------------------------------------------------------------------------- 1 | class TreeNode { 2 | constructor(element){ 3 | this.element = element; 4 | this.left = null; 5 | this.right = null; 6 | } 7 | } 8 | 9 | module.exports = TreeNode; -------------------------------------------------------------------------------- /deque.md: -------------------------------------------------------------------------------- 1 | # Deque 2 | 3 | ## What is Deque? 4 | 5 | > _In computer science, a double-ended queue **\(Deque\)** is an abstract data type that generalizes a Queue, for which elements can be added to or removed from either the front \(head\) or back \(tail\)_ - Wikipedia 6 | 7 | ## List Of Operations Available 8 | 9 | * **AddFront** : Insert an element at the front of the Deque. 10 | * **AddBack** : Insert an element at the back of the Deque. 11 | * **RemoveFront** : Remove an element from front. 12 | * **RemoveBack** : Remove an element from the back. 13 | * **PeekBack** : This method returns the first element of the Deque same as _**queue**_ [front](https://dev.to/swarup260/data-structures-algorithms-in-javascript-queue-59al#front) method. 14 | * **PeekFront** : This method returns the end element of the Deque same as _**stack**_ [peek](https://dev.to/swarup260/data-structures-algorithms-in-javascript-stack-1ilb#peek) method. 15 | * **Size** : Return Size of the deque. 16 | * **isEmpty** : Check if the Deque is empty if empty return true else false. 17 | * **Clear** : Reset the Deque. 18 | 19 | ## Implementation of Deque in Javascript 20 | 21 | Deque class is similar to [**queue**](https://dev.to/swarup260/data-structures-algorithms-in-javascript-queue-59al#queue). 22 | 23 | ```javascript 24 | class Deque { 25 | constructor() { 26 | this.items = {}; 27 | this.count = 0; 28 | this.lowestCount = 0; 29 | } 30 | } 31 | ``` 32 | 33 | #### **AddBack** 34 | 35 | Deque _addback_ method is similar to queue's [enqueue](https://dev.to/swarup260/data-structures-algorithms-in-javascript-queue-59al#enqueue) method. 36 | 37 | ```javascript 38 | addBack(element) { 39 | this.items[this.count] = element; 40 | this.count++; 41 | } 42 | ``` 43 | 44 | #### **AddFront** 45 | 46 | When adding an element at the front Deque, There are three scenarios, 1. If the Deque is Empty then same as addBack method \({1}\) 2. When an element is removed from the front of the Deque \({2}\),lowestCount will be greater > zero, 47 | 48 | * Then decrement the _count_ 49 | * Assign the element to that object key. 50 | 1. If the lowestCount is equal to zero then, we need to shift the element by one position right and free the first position and assign the element to that object key \({3}\) 51 | 52 | ```javascript 53 | addFront(element) { 54 | if (this.isEmpty()) { //1 55 | this.addBack(element); 56 | } else if (this.lowestCount > 0) { //2 57 | this.lowestCount --; 58 | this.items[this.lowestCount] = element; 59 | } else { //3 60 | for (let index = this.count; index > 0; index--) { 61 | this.items[index] = this.items[index -1]; 62 | } 63 | this.count ++; 64 | this.items[0] = element; 65 | } 66 | return true; 67 | } 68 | ``` 69 | 70 | > For removing an element from the Deque, we first need to check, if the Deque is not Empty else return _undefined_. 71 | 72 | #### **RemoveFront** 73 | 74 | While an element from the front of the Deque is as [_dequeue_](https://dev.to/swarup260/data-structures-algorithms-in-javascript-queue-59al#dequeue) method of Queue 75 | 76 | ```javascript 77 | removeFront() { 78 | if (this.isEmpty()) { 79 | return undefined; 80 | } 81 | 82 | let result = this.items[this.lowestCount]; 83 | delete this.items[this.lowestCount]; 84 | this.lowestCount++; 85 | return result; 86 | 87 | } 88 | ``` 89 | 90 | #### **RemoveBack** 91 | 92 | While an element from the back of the Deque is as [_pop_](https://dev.to/swarup260/data-structures-algorithms-in-javascript-stack-1ilb#pop) method of the Stack 93 | 94 | ```javascript 95 | removeBack() { 96 | if (this.isEmpty()) { 97 | return undefined; 98 | } 99 | let result = this.items[this.count - 1]; 100 | delete this.items[this.count - 1]; 101 | this.count--; 102 | return result; 103 | } 104 | ``` 105 | 106 | [**size**](https://dev.to/swarup260/data-structures-algorithms-in-javascript-queue-59al#size)**,**[**clear**](https://dev.to/swarup260/data-structures-algorithms-in-javascript-queue-59al#clear)**,**[**isEmpty**](https://dev.to/swarup260/data-structures-algorithms-in-javascript-queue-59al#isempty) will be same as queue methods 107 | 108 | you get the full source [here](https://github.com/swarup260/Learning_Algorithms/blob/master/data_structure/Dequeue.js) 109 | 110 | ### Conclusion : 111 | 112 | | Methods | Complexity | 113 | | :--- | :---: | 114 | | addback | O\(1\) | 115 | | addfront | O\(1\) | 116 | | removeFront | O\(1\) | 117 | | removeBack | O\(1\) | 118 | 119 | -------------------------------------------------------------------------------- /dictionary.md: -------------------------------------------------------------------------------- 1 | # Dictionary 2 | 3 | > _A dictionary is a general-purpose data structure for storing a group of objects. A dictionary has a set of keys and each key has a single associated value._ - [_Wikibooks_](https://en.wikibooks.org/wiki/A-level_Computing/AQA/Paper_1/Fundamentals_of_data_structures/Dictionaries#:~:text=A%20dictionary%20is%20a%20general,has%20a%20single%20associated%20value.&text=Different%20languages%20enforce%20different%20type,often%20implemented%20as%20hash%20tables.) 4 | 5 | ## List Of Operations Available 6 | 7 | * **set**: insert a new key-value pair in the dictionary. 8 | * **get**: return the value if the key is present. 9 | * **remove**: remove key-value pair from the dictionary if present. 10 | * **hasKey**: check if the key exists for not. 11 | * **keys**: return all the keys in the dictionary. 12 | * **values**: return all the values in the dictionary. 13 | * **keyValues** : return an array containing all the pairs. 14 | * **forEach**: takes callback function to perform an operation on each pair. 15 | 16 | > _A dictionary is also known as a map,symbol table, and an associative array_ 17 | 18 | ### Implementation of Dictionary in Javascript 19 | 20 | We start by defining a class, **Dictionary** with property a _**table**_. Property table will be javascript Object which will holds items in it. In a dictionary, the ideal would be to store keys of type string and any type of value \(from primitive type such as numbers, a string, to complex objects\). However, because JavaScript is not strongly typed, we cannot guarantee the key will be a string .i.e, 21 | 22 | > We first transform the key whatever object is passed as the key into a string to make it easier to search and retrieve values from the Dictionary class. 23 | > 24 | > Values will be Stored as **table\[stringify\(Key\)\] = new KeyValues\(key,value\)**; 25 | 26 | ```javascript 27 | class Dictionary { 28 | constructor(toStrFn = toStringFunc) { 29 | this.table = {}; 30 | this.toStrFn = toStrFn; 31 | } 32 | } 33 | ``` 34 | 35 | > Default String Stringify function \`\`\`javascript 36 | 37 | function toStringFunc\(key\) { if \(key == null\) { return 'NULL' } if \(key == undefined\) { return 'UNDEFINED' } if \(\(typeof key == "string"\) \|\| key instanceof String\) { return `${key}`; } return key.toString\(\); } 38 | 39 | ```text 40 | ## Set 41 | When inserting a key-value pair, we will check if the key & value is not null. 42 | 43 | Else : 44 | * Stringify the key using the default string method 45 | * Create a new instance of KeyPair. 46 | * Add the stringify value as the key and value as the instance of Keypair. 47 | 48 | > Dictionary Keys are unique.You can't have two or more keys to the same value . if present then it will just override the old value with the new one. 49 | 50 | ```javascript 51 | set(key, value) { 52 | if (key != null & value != null) { 53 | const stringKey = this.toStrFn(key); 54 | this.table[stringKey] = new KeyValue(key, value); 55 | return true; 56 | } 57 | return false; 58 | } 59 | ``` 60 | 61 | ### KeyValue Class 62 | 63 | ```javascript 64 | class KeyValue{ 65 | constructor(key, value){ 66 | this.key = key; 67 | this.value = value; 68 | } 69 | toString(){ 70 | return `[#${this.key} , ${this.value}]` 71 | } 72 | } 73 | ``` 74 | 75 | ## HasKey 76 | 77 | To check if the key is present or not, We will Stringify the key and check if its present or not. 78 | 79 | ```javascript 80 | hasKey(key) { 81 | return this.table[this.toStrFn(key)] !== null; 82 | } 83 | ``` 84 | 85 | ## Remove 86 | 87 | When removing a key-value pair, We first need to check if the key is present in the Dictionary using the HasKey method. If present then deletes the key-value pair. 88 | 89 | ```javascript 90 | remove(key) { 91 | if (this.hasKey(key)) { 92 | delete this.table[this.toStrFn(key)]; 93 | return true; 94 | } 95 | return false; 96 | } 97 | ``` 98 | 99 | ## get 100 | 101 | If a key-value pair, with a key, exists then return value or else null. As we know that we first we stringify the key and set that as the Object key and value as the instance of KeyValue. ie. 102 | 103 | * Stringify the key. 104 | * Return the stringify key's KeyValue value. 105 | 106 | ```javascript 107 | get(key) { 108 | const keyValuesPair = this.table[this.toStrFn(key)]; 109 | return keyValuesPair != null ? keyValuesPair.value : null; 110 | } 111 | ``` 112 | 113 | **KeyValues** 114 | 115 | This method will return all the stored _key-value pair_ in the **Dictionary class**, 116 | 117 | * Initialize an array _keyValuePairs_ 118 | * Iterate _table_ property, if the key exists then push to keyValuePairs array 119 | * Return the keyValuePairs. 120 | 121 | ```javascript 122 | keyValues() { 123 | const keyValuePairs = []; 124 | for (const key in this.table) { 125 | if (this.table.hasOwnProperty(key)) { 126 | keyValuePairs.push(this.table[key]) 127 | } 128 | } 129 | return keyValuePairs; 130 | } 131 | ``` 132 | 133 | ## Keys 134 | 135 | This method returns all the key-value pairs keys. We will evoke the KeyValues extract the **keys** using [Array.prototype.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map). Alternative use can also do the same thing using for loop. 136 | 137 | ```javascript 138 | keys() { 139 | return this.keyValues().map(element => element.key); 140 | } 141 | ``` 142 | 143 | ## Values 144 | 145 | This method returns all the key-value pairs values. We will evoke the KeyValues extract the **values** using Array.prototype.map 146 | 147 | ```javascript 148 | values() { 149 | return this.keyValues().map(element => element.value); 150 | } 151 | ``` 152 | 153 | ## ForEach 154 | 155 | ForEach is an iterator function, Which allows us to loop the all key-value pair present in the Dictionary class. But, the same can be applied for other data structures too. 156 | 157 | * We evoke the KeyValues and get all the key-value pairs. 158 | * We will iterate over the individual pairs and execute the callback until the condition is true. 159 | 160 | ```javascript 161 | forEach(callback) { 162 | let keyValuePairs = this.keyValues(); 163 | for (let index = 0; index < keyValuePairs.length; index++) { 164 | const result = callback(keyValuePairs[index].key, keyValuePairs[index].value); 165 | if (result == false) { 166 | break; 167 | } 168 | 169 | } 170 | } 171 | ``` 172 | 173 | you get the full source [here](https://github.com/swarup260/Learning_Algorithms/blob/master/data_structure/Dictionary.js) 174 | 175 | > [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) ES6 ,Is similar to Dictionary . 176 | 177 | ### Conclusion : 178 | 179 | | Methods | Complexity | 180 | | :--- | :---: | 181 | | set | O\(n\) | 182 | | get | O\(1\) | 183 | | remove | O\(1\) | 184 | | keys | O\(n\) | 185 | | values | O\(n\) | 186 | | KeyValues | O\(n\) | 187 | | forEach | O\(n\) | 188 | 189 | -------------------------------------------------------------------------------- /hashtable/README.md: -------------------------------------------------------------------------------- 1 | **Hash Table**. is a widely used data structure for its faster lookup. Like Arrays where data is stored in an indexed structure, whereas hashtable use hash mapped layout. 2 | 3 | So, in general, it consists of two things : 4 | 5 | - Table: holds the data in an array or an object. 6 | - Hash function: To calculate the hash for the elements in the hash table. 7 | 8 | ## What is Hash Table? 9 | 10 | > _A Hash table (*hash map*) is a data structure that implements an associative array abstract data type, a structure that can map keys to value. A hash table uses a hash function to compute an *index*, also called a *hash code*, into an array of *buckets* or *slots*, from which the desired value can be found._ - [wikipedia](https://en.wikipedia.org/wiki/Hash_table#:~:text=In%20computing%2C%20a%20hash%20table,desired%20value%20can%20be%20found) 11 | 12 | ## What is Hash Function? 13 | 14 | > *A hash function is any function that can be used to map a data set of arbitrary size to a data set of a fixed size, which falls into the hash table. The values returned by a hash function are called hash values, hash codes, hash sums, or simply hashes.* - [wikipedia](https://en.wikipedia.org/wiki/Hash_function) 15 | 16 | Different of Hash Function : 17 | - djb2 18 | - loose loose 19 | - sdbm 20 | 21 | for more information [here](http://www.cse.yorku.ca/~oz/hash.html). 22 | 23 | List of Available Methods : 24 | 25 | - **put**: Insert an element (it can also update) 26 | - **remove**: Remove an element 27 | - **get**: Get the inserted element 28 | 29 | ## Implementation of Hash Table in JavaScript 30 | 31 | if you just want the source code find [here](https://github.com/swarup260/Learning_Algorithms/blob/master/data_structure/HashTable.js). 32 | 33 | So, let’s started with defining a class ES6 HashTable; It will be the same as [Dictionary](https://dev.to/swarup260/data-structures-algorithms-in-javascript-dictionary-3b7f). 34 | 35 | ```javascript 36 | 37 | class HashTable { 38 | constructor() { 39 | this.table = {}; 40 | } 41 | } 42 | 43 | ``` 44 | 45 | ## Hash Function 46 | 47 | we will use the lose lose hash function, but you can use any of the above hash function 48 | 49 | 1. If its a number return number 50 | 2. If it's not a number then, stringify the key add up all the char with its ASCII value, we can use [charCodeAt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt) and divide it with an arbitrary number to work with lower numbers. 51 | 52 | ```javascript 53 | _loseloseHashCode(key) { 54 | if (typeof key == "number") { 55 | return key; 56 | } 57 | const keyString = toStringFunc(key); 58 | let code = 0; 59 | for (let index = 0; keyString < key.length; index++) { 60 | code += keyString.charCodeAt(index); 61 | } 62 | return code % 37; 63 | } 64 | ``` 65 | 66 | Before implementing other methods, I want to clarify the differences between a **HashMap** and **HashSet**. HashMap behavior is more like a Map or dictionary, whereas elements are hash and stored as key-value pairs. In HashSet is stored as Set. more information visited here [here](https://www.javatpoint.com/difference-between-hashset-and-hashmap) or [here](https://www.geeksforgeeks.org/difference-between-hashmap-and-hashset/).But in this article ,I will explain using hashmap. 67 | 68 | ## Put 69 | 70 | 1. Check whether the keys and value in not NULL if yes return false. 71 | 2. If key and value is not null then calculate the hash using the above hash function method. 72 | 3. Set the table property's key as a hash value and value as key-value pairs same as [KeyValue class](https://dev.to/swarup260/data-structures-algorithms-in-javascript-dictionary-3b7f) of dictionary. 73 | 74 | ```javascript 75 | put(key, value) { 76 | if (key != null && value != null) { 77 | const keyHash = this.getHashCode(key); 78 | this.table[keyHash] = new KeyValue(key, value); 79 | return true; 80 | } 81 | return false; 82 | } 83 | ``` 84 | 85 | ## Remove 86 | 87 | 1. Calculate the hash using the above hash function method. 88 | 2. Check whether the element with the key is present in the table property if not return undefined. 89 | 3. If it's present delete the key in the table. 90 | 91 | ```javascript 92 | remove(key) { 93 | const keyHash = this.getHashCode(key); 94 | if (this.table[keyHash]) { 95 | const value = this.table[keyHash]; 96 | delete this.table[keyHash]; 97 | return value; 98 | } 99 | return undefined; 100 | } 101 | ``` 102 | 103 | ## Get 104 | 105 | 1. Calculate the hash using the above hash function method. 106 | 2. Check whether the element with the key is present in the table property if not return undefined. 107 | 108 | ```javascript 109 | get(key) { 110 | const keyHash = this.getHashCode(key); 111 | return this.table[keyHash] != null ? this.table[keyHash].value : undefined; 112 | } 113 | ``` 114 | 115 | you get the full source [here](https://github.com/swarup260/Learning_Algorithms/blob/master/data_structure/HashTable.js). 116 | 117 | So, in an ideal case, the Hash function always produces a different hash for any given key. 118 | 119 | Eg: Let say , we want to store the list of email address against its name 120 | 121 | ``` 122 | dave : dave@gmail.com 123 | 124 | john : john@gmail.com 125 | ``` 126 | so its hash value will be **dave: 9** and **john:24** use above hash function. 127 | But that's not the case, it may produce the same set of the hash value for two or more keys. This phenomenon is also known as **Collision** or **Hash collision**. 128 | 129 | Eg: Now, for 130 | ``` 131 | nathan: nathan@gmail.com 132 | 133 | sargeras: sargeras@gmail.com 134 | ``` 135 | 136 | ![Hash collision](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4nnsbvf7w2qu0v74nl5d.png) 137 | _Fig: Hash Collision in Hashtable_ 138 | 139 | for both the hash value will be 5 respectively use above hash function. 140 | 141 | What is Hash Collision? 142 | 143 | > *In computer science a **hash collision** or clash is when two pieces of data in a hash table share the same hash value. The hash value, in this case, is derived from a hash function that takes a data input and returns a fixed length of bits* - [wikipedia](https://en.wikipedia.org/wiki/Hash_collision#:~:text=In%20computer%20science%2C%20a%20hash,a%20fixed%20length%20of%20bits.&text=Malicious%20users%20can%20take%20advantage,%2C%20access%2C%20or%20alter%20data) 144 | 145 | They are various methods to resolve hash collision : 146 | 147 | - **Open Addressing** 148 | - Some types of probing are [linear probing](https://en.wikipedia.org/wiki/Linear_probing), [double hashing](https://en.wikipedia.org/wiki/Double_hashing), and [quadratic probing](https://en.wikipedia.org/wiki/Quadratic_probing) 149 | - **Separate Chaining** 150 | - **Cache-Conscious Collision Resolution** 151 | 152 | I will explain in detail in my next blogs. 153 | 154 | ## Conclusion 155 | 156 | | Algorithm | Average | Worst case | 157 | | ------------- |:-------------:| :-------------:| 158 | | Space | O(n) | O(n) | 159 | | Search | O(1) | O(n) | 160 | | Insert/Put | O(1) | O(n) | 161 | | Delete/Remove | O(1) | O(n) | -------------------------------------------------------------------------------- /hashtable/hashtablelinearprobing.md: -------------------------------------------------------------------------------- 1 | # What is HashTable Linear Probing ? 2 | 3 | > \*\* 4 | 5 | ## List Of Operations Available 6 | 7 | * All methods will same as the [**single linked list**](./) . we will only overwrite method. 8 | 9 | . 10 | 11 | ### Implementation of HashTable in Javascript : 12 | 13 | ```javascript 14 | class HashTable { 15 | constructor() { 16 | this.table = {}; 17 | } 18 | } 19 | ``` 20 | 21 | ## Put 22 | 23 | ```javascript 24 | put(key, value) { 25 | if (key != null && value != null) { 26 | const hashKey = this.getHashCode(key); 27 | if (this.table[hashKey] == null) { 28 | this.table[hashKey] = new KeyValue(key, value); 29 | } else { 30 | 31 | let position = hashKey + 1; 32 | while (this.table[position] != null) { 33 | position++; 34 | } 35 | this.table[position] = new KeyValue(key, value); 36 | } 37 | return true; 38 | } 39 | return false; 40 | } 41 | ``` 42 | 43 | ## Remove 44 | 45 | ```javascript 46 | remove(key) { 47 | const hashKey = this.getHashCode(key); 48 | if (this.table[hashKey] != null) { 49 | if (this.table[hashKey].key == key) { 50 | delete this.table[hashKey]; 51 | this.verifyRemoveSideEffect(key, hashKey); 52 | return true; 53 | } 54 | 55 | let position = hashKey + 1; 56 | while (this.table[position] != null && this.table[position].key != key) { 57 | position++; 58 | } 59 | 60 | if (this.table[position] && this.table[position].key == key) { 61 | delete this.table[position]; 62 | this.verifyRemoveSideEffect(key, position); 63 | return true; 64 | } 65 | } 66 | return false; 67 | 68 | } 69 | ``` 70 | 71 | ## Get 72 | 73 | ```javascript 74 | get(key) { 75 | const hashKey = this.getHashCode(key); 76 | if (this.table[hashKey] != null) { 77 | if (this.table[hashKey].key == key) { 78 | return this.table[hashKey].value; 79 | } 80 | 81 | let position = hashKey + 1; 82 | while (this.table[position] != null && this.table[position].key != key) { 83 | position++; 84 | } 85 | 86 | if (this.table[position] && this.table[position].key == key) { 87 | return this.table[position].value; 88 | } 89 | } 90 | return undefined; 91 | } 92 | ``` 93 | 94 | ## VerifyRemoveSideEffect 95 | 96 | ```javascript 97 | verifyRemoveSideEffect(key, removePosition) { 98 | const hashKey = this.getHashCode(key); 99 | let position = removePosition +1; 100 | while(this.table[position] != null){ 101 | const hashKeyPosition = this.getHashCode(this.table[position].key); 102 | if (hashKeyPosition <= hashKey || hashKeyPosition <= removePosition ) { 103 | this.table[removePosition] = this.table[position]; 104 | delete this.table[position]; 105 | removePosition = position; 106 | } 107 | position ++; 108 | } 109 | } 110 | ``` 111 | 112 | ### Conclusion : 113 | 114 | | Methods | Complexity | 115 | | :--- | :---: | 116 | 117 | 118 | -------------------------------------------------------------------------------- /hashtable/hashtableseparatechaining.md: -------------------------------------------------------------------------------- 1 | # HashTableSeparateChaining 2 | 3 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { StackObject, Stack} = require('./data_structure/Stack') 2 | 3 | const stack = new Stack(); 4 | 5 | stack.push(1); 6 | stack.push(5); 7 | console.log(stack.items) 8 | console.log(stack.toString()) 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /linked-list/README.md: -------------------------------------------------------------------------------- 1 | # Linked List 2 | 3 | -------------------------------------------------------------------------------- /linked-list/circularlinkedlist.md: -------------------------------------------------------------------------------- 1 | # Circular linked list 2 | 3 | > _Circular linked list is a linked list where all nodes are connected to form a circle. There is no NULL at the end. A circular linked list can be a singly circular linked list or doubly circular linked list._ - geeksforgeeks.org 4 | 5 | ![Circular Single Linked List](https://dev-to-uploads.s3.amazonaws.com/i/q1q3g8lilm941e9jh82l.png) 6 | 7 | **Fig**: Circular Single Linked List 8 | 9 | ![Circular Doubly Linked List](https://dev-to-uploads.s3.amazonaws.com/i/9b96w073q2kgdddo2im9.png) 10 | 11 | **Fig**: Circular Doubly Linked List 12 | 13 | ## List Of Operations Available 14 | 15 | * All methods will same as [**single linked list**](https://dev.to/swarup260/data-structures-algorithms-in-javascript-single-linked-list-part-1-3ghg). Only overwrite the _insert_, _push_ and _removeAt_ methods 16 | 17 | ## Implementation of Circular linked list in Javascript 18 | 19 | The CircularLinkedList class does not need and additional properties, so we can simply extend the LinkedList Class, only overwrite the required methods. 20 | 21 | ```javascript 22 | class CircularLinkedList extends LinkedList { 23 | constructor(){ 24 | super(); 25 | } 26 | } 27 | ``` 28 | 29 | ## Push 30 | 31 | Push method will append an element at the end of the LinkedList. While appending an element \(node\), There are two scenarios : 1. LinkedList is **Empty**. 32 | 33 | * set the linked list head property to the new node. 34 | * set new node's next to the head, since circular LinkedList doesn't have a NULL pointer at the end. 35 | 36 | 1. LinkedList is **Not Empty**. 37 | * loop till the end. 38 | * set the End node to the new node i.e end node.next to the node. 39 | * set new node's next to the head. 40 | 41 | after pushing an element to linked list increment the counter 42 | 43 | ```javascript 44 | push(element){ 45 | let node = new Node(element); 46 | let current = this.head; 47 | if (current == undefined) { 48 | this.head = node; 49 | node.next = this.head; 50 | } else { 51 | while(current.next != null){ 52 | current = current.next; 53 | } 54 | current.next = node; 55 | node.next = this.head; 56 | } 57 | this.count++; 58 | return this; 59 | } 60 | ``` 61 | 62 | ## Insert 63 | 64 | Insert method will insert an element at a given position. The position must be greater than zero and less than or equal to count \(length of LinkedList\). If not return undefined. 1. The index is Zero 65 | 66 | * Empty 67 | * Same as push method condition, when LinkedList is empty 68 | * Not Empty 69 | * set the new node to the current head 70 | * head to the new node 71 | 1. The index is equal to count .ie length of LinkedList 72 | 2. Get the \(index - 1\) element using the getElementAt method, store as the previous Element. 73 | 3. Set previous to the new node. And node's next to the head. 74 | 4. The index is greater than Zero 75 | 5. Get the \(index - 1\) element using the getElementAt method, store as the previous Element. 76 | 6. The indexed element will be previous. next, store as current. 77 | 7. Set previous to the new node. And node's next to previous. 78 | 79 | after pushing an element to linked list increment the counter 80 | 81 | ![Insert](https://dev-to-uploads.s3.amazonaws.com/i/et6mdpc3hzey5l6fbuop.png) 82 | 83 | ```javascript 84 | insert(element,index){ 85 | if (index >= 0 && index <= this.count) { 86 | const node = new Node(element); 87 | let current = this.head 88 | if (index == 0) { 89 | if (this.head == undefined) { 90 | this.head = node; 91 | node.next = this.head; 92 | }else{ 93 | node.next = current; 94 | this.head = node; 95 | } 96 | }else if (index == this.count) { 97 | const previous = this.getElementAt(index -1); 98 | previous.next = node; 99 | node.next = this.head; 100 | }else{ 101 | const previous = this.getElementAt(index -1); 102 | current = previous.next; 103 | previous.next = node; 104 | node.next = current; 105 | } 106 | this.count++; 107 | return this; 108 | } 109 | return undefined; 110 | } 111 | ``` 112 | 113 | ## RemoveAt 114 | 115 | RemovAt method will remove an element at a given position. The position must valid the index's out of bound error, by checking that the position is greater than and equal to zero and less than count. If not return undefined. 1. LinkedList is Empty 116 | 117 | * return undefined 118 | 1. The index is Zero. 119 | * Move the head to the next node. 3. The index is equal to the count - 1. 120 | 121 | * Get the \(index - 1\) element using the getElementAt method, store as the previous Element. 122 | * Set the previous's next to the head. 123 | 124 | ![Removing the tail element](https://dev-to-uploads.s3.amazonaws.com/i/eicjw07qubdm2v6lrkn1.png) 125 | 126 | 1. The index is greater than Zero 127 | * Get the \(index - 1\) element using the getElementAt method, store as the previous Element. 128 | * The indexed element will be previous.next, store as current. 129 | * set the previous.next to the current.next. 130 | 131 | ![Removing any element](https://dev-to-uploads.s3.amazonaws.com/i/nz1wcce60nuhskwhjgwd.png) 132 | 133 | after removing an element from the linked list decrement the counter 134 | 135 | ```javascript 136 | removeAt(index){ 137 | if (index >= 0 && index < this.count) { 138 | if (this.isEmpty()) { 139 | return undefined; 140 | } 141 | let current = this.head 142 | if (index == 0) { 143 | this.head = current.next; 144 | } else if(index == this.count-1) { 145 | const previous = this.getElementAt(index-1); 146 | current = previous.next; 147 | previous.next = this.head; 148 | }else{ 149 | const previous = this.getElementAt(index -1); 150 | current = previous.next; 151 | previous.next = current.next; 152 | } 153 | 154 | this.count --; 155 | return current.element; 156 | } 157 | return undefined; 158 | } 159 | ``` 160 | 161 | Get the full source code [here](https://github.com/swarup260/Learning_Algorithms/blob/master/data_structure/CircularLinkedList.js) 162 | 163 | ### Conclusion : 164 | 165 | Complexity will be the same as Single Linked List. This blog only covers a singly circular linked list. But the doubly circular linked list will similar to the doubly linked list. 166 | 167 | -------------------------------------------------------------------------------- /linked-list/doublylinkedlist.md: -------------------------------------------------------------------------------- 1 | # DoublyLinkedList 2 | 3 | ## What is the Doubly linked list? 4 | 5 | > _A Doubly Linked List contains an extra pointer, typically called the previous pointer, together with next pointer and data which are there in the singly linked list._ - geeksforgeeks.org 6 | 7 | ![Doubly Linked List](https://thepracticaldev.s3.amazonaws.com/i/5r9178k7elaqve5sjr4m.png) 8 | 9 | ### List Of Operations Available 10 | 11 | * All methods will same as [**single linked list**](https://dev.to/swarup260/data-structures-algorithms-in-javascript-single-linked-list-part-1-3ghg).We only overwrite the _insert_, _push_ and _removeAt_ methods. 12 | 13 | ### Implementation of Doubly linked list in Javascript 14 | 15 | The doubly linked list is a special type of linked list. We will just extend the linked list class i.e inherit the **LinkedList** class. we call the parent constructor by _**super**_ keyword to initialize the **count** and **head** properties of the Doubly linked list. besides, it has a **tail** property which refers to the end of the doubly linked list 16 | 17 | ```javascript 18 | class DoubleLinkedList extends LinkedList { 19 | constructor(func) { 20 | super(func); 21 | this.tail = undefined; 22 | } 23 | } 24 | ``` 25 | 26 | DoubleLinkedList provides a way of iterating it from start to end or vice versa. We can go forward using _next_ pointer or backward using _previous_ pointer, for this behavior, we will keep track of the previous element in each node, therefore, we will define a **DoublyNode** Which will extend the **Node class**, _element_ and _next_ properties will be initialized by parent constructor and a _previous_ property to keep track of the previous element. 27 | 28 | ```javascript 29 | class DoublyNode extends Node { 30 | constructor(element, next, previous) { 31 | super(element, next); 32 | this.previous = previous; 33 | } 34 | } 35 | ``` 36 | 37 | > **All methods implementation will be similar to the single linked list. In addition to the** _**next**_ **pointer, we also have the** _**previous**_ **pointer.** 38 | 39 | ### Push 40 | 41 | When Pushing an element to a doubly-linked list, we have two scenarios: 42 | 43 | * Doubly-linked list is **empty**. 44 | * Doubly-linked list is not empty and appends element at the end. 45 | 46 | First, We will create a **DoublyNode** passing element as its _value_ if the head is _**undefined**_ then assign **head pointer** to the node **\({1}\)** and also tail **\({2}\)**. Since the end node points to the **tail pointer**. 47 | 48 | Secondly, If the doubly linked list is not empty we will define a current variable equal to tail **\({3}\)**, points the new node to the **current.next** **\({4}\)** , **node.next** to current **\({5}\)** and **node.next** **\({6}\)** to the tail. 49 | 50 | ```javascript 51 | push(element) { 52 | let node = new DoublyNode(element); 53 | if (this.head == undefined) { 54 | this.head = node; //1 55 | this.tail = node; //2 56 | } else { 57 | let current = this.tail; //3 58 | current.next = node; //4 59 | node.previous = current; //5 60 | this.tail = node; //6 61 | 62 | } 63 | this.count++; 64 | } 65 | ``` 66 | 67 | ### Insert 68 | 69 | To insert an element at a given the position; We validate the index, ie. **index the must be greater than zero and less than and equal to count**, there are three scenarios, 70 | 71 | * Insert an element at the start of the list **\(Index == 0\)**. 72 | * We check if the list's head is undefined : 73 | * If undefined then the same as the push method \(head is undefined\) **\({2}\)**. Set head **\({3}\)** and tail **\({4}\)** to the new Node. 74 | * Else, move the list's head to the new node.Define current variable equal to head **\({1}\)**,Set node.next to current **\({6}\)**,current.previous to node **\({5}\)** and head to the new Node **\({7}\)**. 75 | 76 | !\[Insert an element at the start of the list\] \([https://thepracticaldev.s3.amazonaws.com/i/zuv8m9qdovl2ngx838tq.png](https://thepracticaldev.s3.amazonaws.com/i/zuv8m9qdovl2ngx838tq.png)\) 77 | 78 | * Insert an element at the end of the list **\(Index == count\)**. 79 | * This is the same push method. When the list is not empty. 80 | 81 | ![Insert an element at the end of the list ](https://thepracticaldev.s3.amazonaws.com/i/veqmu46l70tpja37ukbi.png) 82 | 83 | * Insert an element at the middle of the list **\(Index == n\)**. 84 | * Adding an element in the middle of the list. First, need to loop through the list until we reach the desired position. In this case, we will loop to index -1, meaning one position before where we desire to insert a new node. 85 | * When we get out of the loop, the previous variable will be a reference to an element before the index where we would like to insert to new element and the current variable. So first, we link the node's next to current and also current's previous to the node, to change the link between previous and current. we need previous.next to the node and node's previous to the previous. 86 | 87 | ![Insert an element at the middle of the list](https://thepracticaldev.s3.amazonaws.com/i/0zsgxj679cuu62htie9o.png) 88 | 89 | ```javascript 90 | insert(element, index) { 91 | if (index >= 0 && index <= this.count) { 92 | 93 | let node = new DoublyNode(element); 94 | let current = this.head; //1 95 | if (index == 0) { 96 | if (this.head == undefined) { //2 97 | this.head = node; //3 98 | this.tail = node; //4 99 | } else { 100 | current.previous = node; //5 101 | node.next = current; //6 102 | this.head = node; //7 103 | } 104 | } else if (index == this.count) { 105 | current = this.tail; 106 | current.next = node; 107 | node.previous = current; 108 | this.tail = node; 109 | } else { 110 | let previous = this.getElementAt(index - 1); 111 | current = previous.next; 112 | previous.next = node; 113 | node.next = current; 114 | node.previous = previous; 115 | current.previous = node; 116 | } 117 | this.count++; 118 | } 119 | } 120 | ``` 121 | 122 | ### RemoveAt 123 | 124 | Remove an element at the specified index, we first check if the linked list is empty else return undefined \({1}\), After that we valid the index's out of bound error, by check is the index, greater than zero and less than count.there are three scenarios, 125 | 126 | * Remove an element at the start of the list 127 | * Remove a node from the start, we just move the head node to head's next Node, To do that we first, define a current variable equal to head, set the head to the current.next. 128 | * If the list count is 1 then set the tail to undefined, as end-node points to tail, we need to unset it by setting tail to undefined, else we set head previous to undefined, we need to unlink the previous head node. 129 | 130 | ![Remove an element at the start of the list](https://thepracticaldev.s3.amazonaws.com/i/3nie9up1jdb1wehpu5ph.png) 131 | 132 | * Remove an element at the end of the list 133 | 134 | ![Remove an element at the end of the list](https://thepracticaldev.s3.amazonaws.com/i/h7tlfwyey26t8ddz1ihx.png) 135 | 136 | * Remove an element at the middle of the list 137 | 138 | ![Remove an element at the middle of the list](https://thepracticaldev.s3.amazonaws.com/i/trkmb5qca6pyw9ckpjof.png) 139 | 140 | ```javascript 141 | removeAt(index) { 142 | if (this.isEmpty()) { 143 | return undefined; 144 | } 145 | if (index >= 0 && index < this.count) { 146 | let current = this.head; 147 | if (index == 0) { 148 | this.head = current.next; 149 | if (this.count == 1) { 150 | this.tail = undefined; 151 | }else{ 152 | this.head.previous = undefined; 153 | } 154 | }else if (index == this.count-1){ 155 | current = this.tail; 156 | this.tail = current.previous; 157 | this.tail.next = undefined; 158 | }else{ 159 | current = this.getElementAt(index); 160 | const previous = current.previous; 161 | // link previous with current's next 162 | previous.next = current.next; 163 | current.next.previous = previous; 164 | } 165 | this.count --; 166 | return current.element; 167 | } 168 | } 169 | ``` 170 | 171 | you get the full source [here](https://github.com/swarup260/Learning_Algorithms/blob/master/data_structure/DoubleLinkedList.js) 172 | 173 | ## Difference between Single Listed List and Doubly Listed List 174 | 175 | | Single Listed List | Doubly Listed List | 176 | | :--- | :---: | 177 | | Uses Less Memory | Takes 2x Memory | 178 | | Simple Implementation | fairly hard Implementation | 179 | | Cannot easily access the previous element | Can easily access the previous element using the previous property | 180 | 181 | #### Conclusion : 182 | 183 | | Methods | Complexity | 184 | | :--- | :---: | 185 | | insert at head | O\(1\) | 186 | | insert at tail | O\(1\) | 187 | | search an element | O\(n\) | 188 | | remove head element | O\(1\) | 189 | | remove any element\(removeAt\) | O\(n\) | 190 | 191 | -------------------------------------------------------------------------------- /linked-list/singlelinkedlist.md: -------------------------------------------------------------------------------- 1 | # Single Linked List 2 | 3 | > _A linked list consists of nodes where each node contains a data field and a reference\(link\) to the next node in the list._ - geeksforgeeks.org 4 | 5 | ![Linked List](https://res.cloudinary.com/practicaldev/image/fetch/s--_PwtVEkJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.educative.io/api/edpresso/shot/5077575695073280/image/5192456339456000) 6 | 7 | ## List Of Operations Available 8 | 9 | * **Push**: Insert an element at the end of the linked list. 10 | * **Insert**: Insert an element at the given index of the linked list. 11 | * **Remove**: Remove the end element of the linked list. 12 | * **RemoveAt**: Remove the element at the given index of the linked list. 13 | * **GetElementAt**: Get the element at the given index of the linked list. 14 | * **IndexOf**: Return the index of the element in the linked list. 15 | 16 | ## Implementation of linked list in Javascript 17 | 18 | Let us define the ES6 class Node, with two properties _data_ and _next_, data property will hold, the data which we will insert in the linked list and next property will hold, the pointer to the next **Node**. A Linked List is just a chain of Node linked to each other by next pointer. **What's a pointer?** _A pointer points to the next member of the list, as you see in the above image_. 19 | 20 | ```javascript 21 | class Node { 22 | constructor(element){ 23 | this.element = element; 24 | this.next = null; 25 | } 26 | } 27 | ``` 28 | 29 | Now, Let's define the ES6 class linked list with three properties, _count_ to track the number elements in the linked list. the _head_ which will always point to the starting node of the linked list but initially it will be **undefined** and _equalFun_ to compare two nodes in the linked list . **In a single Linked list, we only have a reference to the head node. So to traverse the linked list we always start with the head and walk through it. So, subsequent method we will always start with head.** 30 | 31 | ```javascript 32 | class LinkedList { 33 | constructor(func) { 34 | this.count = 0; 35 | this.head = undefined; 36 | this.equalFunc = func || defaultEq; 37 | } 38 | } 39 | ``` 40 | 41 | ### Push 42 | 43 | When adding an element at the end of the linked list, there can be two scenarios: 44 | 45 | * When the head is **undefined** i.e linked list is empty. 46 | * When the linked list is not empty we need to append at the end. 47 | 48 | First, we create a Node passing element as its value if the head is undefined then assign head to the node **\({1}\)** else ,we will define a _current_ variable equal to head and loop until we reach the end of the linked list i.e when node's next is null **\({2}\)** and assign the end Node's next to the node **\({3}\)**, after adding an element will always increment the count variable **\({4}\)**. 49 | 50 | ```javascript 51 | push(element) { 52 | const node = new Node(element); 53 | let current = this.head; 54 | if (this.head == undefined) { 55 | this.head = node; //1 56 | }else{ 57 | while (current.next != null) { //2 58 | current = current.next 59 | } 60 | current.next = node; //3 61 | } 62 | this.count++ //4; 63 | return; 64 | } 65 | ``` 66 | 67 | ### GetElementAt 68 | 69 | To get an element by its **index** we will first define a variable _node_, referring to **head** **\({1}\)**, we valid the index's out of bound error, by check is the index, greater than zero and less than count. **\({2}\)**; if not then return **undefined** **\({5}\)**, Now, iterate over the linked list starting from 0 to the index and **\({3}\)**, return the _node_ **\({4}\)**. This method will be very useful in insert and remove an element from any position in the linked list. 70 | 71 | ```javascript 72 | getElementAt(index) { 73 | let node = this.head; // 1 74 | if (index >= 0 && index < this.count) { //2 75 | for (let i = 0; i < index; i++) { //3 76 | node = node.next; 77 | } 78 | return node; //4 79 | } 80 | return undefined; //5 81 | } 82 | ``` 83 | 84 | ### Insert 85 | 86 | Insert an element at a given the position; the index must be greater than zero and less than and equal to count, there are two scenarios, we will first define a variable node which refers to the head. 87 | 88 | * _**index** is equal to zero_ **\({1}\)** 89 | * check if the head is undefined or not 90 | * if undefined than head equal to the node 91 | * else change the head node to the new node and node's next to the previous head. 92 | 93 | ![Insert element at zero index](https://thepracticaldev.s3.amazonaws.com/i/vp3za0jbztn5tmukevwr.png) 94 | 95 | * _**index** is greater than zero_ **\({2}\)** 96 | * adding an element in the middle or at the end of the list. First, need to loop through the list until we reach the desired position. In this case, we will loop to index -1, meaning one position before where we desire to insert a new node 97 | * When we get out of the loop, the _previous_ variable will be reference to an element before the index where we would like to insert to new element, and the _current_ variable . 98 | * So , first we link the node's _next_ to _current_ and then change the link between _previous_ and current. we need _previous.next_ to the node. 99 | 100 | ![Insert element at any index](https://thepracticaldev.s3.amazonaws.com/i/kbtmyg5cnoswcjhok0so.png) 101 | 102 | ```javascript 103 | insert(element, postion) { 104 | if (postion >= 0 && postion <= this.count) { 105 | const node = new Node(element); 106 | let current = this.head; 107 | if (postion == 0) { //1 108 | if (this.head == undefined) { 109 | this.head = node; 110 | } 111 | this.head = node; 112 | node.next = current; 113 | } else { 114 | let previous = this.getElementAt(postion - 1); 115 | current = previous.next; 116 | node.next = current; 117 | previous.next = node; 118 | } 119 | this.count++; 120 | } 121 | } 122 | ``` 123 | 124 | ### IndexOf 125 | 126 | This method will return the _index_ of the given element if exists else return **-1** **\({4}\)** . To find the _index_ of the element, we will start with the head element **\({1}\)** and loop until the element is found **\({2}\)** and returns its index **\({3}\)** . 127 | 128 | ```javascript 129 | indexOf(element) { 130 | let current = this.head; //1 131 | for (let index = 0; index < this.count && current != null; index++) { 132 | if (current.element == element) { //2 133 | return index; 134 | } 135 | current = current.next; //3 136 | } 137 | return -1; //4 138 | } 139 | ``` 140 | 141 | ### RemoveAt 142 | 143 | Remove an element at the specified index, we first check if the linked list is _empty_ else return undefined **\({1}\)** ,After that we valid the index's out of bound error, by check is the index, greater than zero and less than _count_. 144 | 145 | * We want to remove the first element i.e index equal to zero **\({2}\)**, shift the head to the next node. We will refer to the first element of the list using the current variable. If we assign head to current's next, we will remove the first element **\({3}\)**. 146 | 147 | ![Remove head node from linked list](https://thepracticaldev.s3.amazonaws.com/i/ux4jidvxkcyjaxuwnkko.png) 148 | 149 | * We want to remove the last element or an element from the linked list, we will use _getElementAt_ method to get the one previous element using index -1 **\({4}\)**, current will be previous's next **\({5}\)**. So, to remove the current node, all we have do is to link the **previous.next** to **current.next** **\({6}\)**. 150 | 151 | ![Remove any node from linked list](https://thepracticaldev.s3.amazonaws.com/i/2hgu2y8ddygea8o45413.png) 152 | 153 | ```javascript 154 | removeAt(index) { 155 | if (this.isEmpty()) { 156 | return undefined; //1 157 | } 158 | if (index >= 0 && index < this.count) { 159 | 160 | let current = this.head 161 | if (index == 0) { // 2 162 | this.head = current.next; //3 163 | } else { 164 | let previous = this.getElementAt(index - 1); //4 165 | current = previous.next; //5 166 | previous.next = current.next; //6 167 | } 168 | this.count--; 169 | return current.element; 170 | } 171 | return undefined; 172 | } 173 | ``` 174 | 175 | ### Remove 176 | 177 | To remove an element, we check if the linked list is not empty. If not then get the index of the element using the _indexOf_ method if the index is **-1** then the element doesn't exist else use the index and remove the element from the linked list using _removeAt_ method. 178 | 179 | ```javascript 180 | remove(element) { 181 | if (this.isEmpty()) { 182 | return undefined; 183 | } 184 | let index = this.indexOf(element); 185 | if (index != -1) { 186 | this.removeAt(index); 187 | } 188 | return undefined; 189 | } 190 | ``` 191 | 192 | you get the full source [here](https://github.com/swarup260/Learning_Algorithms/blob/master/data_structure/LinkedList.js) 193 | 194 | ### Conclusion : 195 | 196 | | Methods | Complexity | 197 | | :--- | :---: | 198 | | insert at any position | O\(n\) | 199 | | insert at head | O\(1\) | 200 | | GetElementAt | O\(n\) | 201 | | indexOf | O\(n\) | 202 | | remove head element | O\(1\) | 203 | | remove any element\(removeAt\) | O\(n\) | 204 | 205 | -------------------------------------------------------------------------------- /linked-list/sortedlistedlist.md: -------------------------------------------------------------------------------- 1 | # SortedListedList 2 | 3 | ## What is Sorted linked list? 4 | 5 | > _A sorted linked list is a list that keeps its elements sorted. To keep all elements sorted, instead of applying a sorting algorithm._ - Learning JavaScript Data Structures and Algorithms Third Edition 6 | 7 | ### List Of Operations Available 8 | 9 | * All methods will same as the [**single linked list**](singlelinkedlist.md) . we will only overwrite the insert method. 10 | 11 | . 12 | 13 | ### Implementation of Sorted linked list in Javascript 14 | 15 | The SortedLinkedList class does not need and additional properties, so we can simply extend the LinkedList Class, only overwrite the required methods. 16 | 17 | ```javascript 18 | class SortedLinkedList extends LinkedList { 19 | constructor(func, CompareFun = defaultCompare){ 20 | super(func); 21 | this.CompareFun = CompareFun; 22 | } 23 | } 24 | ``` 25 | 26 | ## Insert 27 | 28 | While Insert an element in SortedLinkedList, There are two scenarios:- 29 | 30 | 1. _**SortedLinkedList is Empty**_ 31 | * Called Parent [Insert Method](singlelinkedlist.md#Insert) and set the index to zero. 32 | 2. _**SortedLinkedList is Not Empty**_ 33 | * Get the Next Sorted Position/Index using the getNextSortIndex method. 34 | * Called Parent [Insert Method](singlelinkedlist.md#Insert) and set the index to Next Sorted Position. 35 | 36 | ```javascript 37 | insert(element, index =0){ 38 | if (this.isEmpty()) { 39 | return super.insert(element,index) 40 | }else{# 41 | const pos = getNextSortIndex(element); 42 | return super.insert(element,pos); 43 | } 44 | } 45 | ``` 46 | 47 | ## GetNextSortIndex 48 | 49 | **This method returns the sorted index by iteratively comparing the element with the linked list's nodes or until all nodes have been iterated.** 50 | 51 | ```javascript 52 | getNextSortIndex(element){ 53 | let current = this.head; 54 | let i = 0; 55 | for (; i < current.next != null ; i++) { 56 | if (this.CompareFun(element,current.element) == Compare.LESS_THAN) { 57 | return i; 58 | } 59 | current = current.next; 60 | } 61 | return i; 62 | } 63 | ``` 64 | 65 | you get the full source [here](https://github.com/swarup260/Learning_Algorithms/blob/master/data_structure/SortedLinkedList.js) 66 | 67 | ## Conclusion 68 | 69 | The complexity of the Sorted Linked List will be the same as Single Linked List. 70 | 71 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "algorithms", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js", 8 | "test": "mocha tests/**/*.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "expect.js": "^0.3.1", 15 | "mocha": "^6.2.2" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /problems/baseConvertor.js: -------------------------------------------------------------------------------- 1 | const {StackObject} = require('../data_structure/Stack'); 2 | 3 | const baseConvertor = ( number , base ) => { 4 | const stack = new StackObject(); 5 | let string = ""; 6 | while (number > 0) { 7 | let rem = Math.floor(number % base); 8 | stack.push(rem); 9 | number = Math.floor(number/base); 10 | } 11 | 12 | while(!stack.isEmpty()){ 13 | 14 | string += `${stack.pop()}` 15 | } 16 | return string; 17 | } 18 | 19 | 20 | 21 | console.log(baseConvertor(10,16)); 22 | -------------------------------------------------------------------------------- /problems/hotPotateo.js: -------------------------------------------------------------------------------- 1 | 2 | const {Queue} = require('../data_structure/Queue'); 3 | 4 | 5 | function HotPotateos (listOfName , number){ 6 | const queue = new Queue(); 7 | const eliminatedList = []; 8 | for (let index = 0; index < listOfName.length; index++) { 9 | queue.equeue(listOfName[index]); 10 | } 11 | while(queue.size() > 1) { 12 | for (let index = 0; index < number; index++) { 13 | queue.equeue(queue.dequeue()); 14 | } 15 | eliminatedPerson = queue.dequeue(); 16 | console.log(`${eliminatedPerson} is eliminated`); 17 | eliminatedList.push(eliminatedPerson) 18 | } 19 | 20 | return { 21 | eliminated : eliminatedList, 22 | winner : queue.dequeue() 23 | } 24 | 25 | } 26 | 27 | console.log(HotPotateos(['swarup', 'rahul', 'rohit' , 'kuldeep', 'shreyash', 'roshan'],4)); 28 | // console.log(HotPotateos(['swarup', 'rahul', 'rohit' , 'kuldeep', 'shreyash', 'roshan'],6)); 29 | -------------------------------------------------------------------------------- /problems/palidrome.js: -------------------------------------------------------------------------------- 1 | const {Queue} = require('../data_structure/Queue'); 2 | const {Dequeue} = require('../data_structure/Dequeue'); 3 | const {StackObject,Stack} = require('../data_structure/Stack') 4 | 5 | /* Using palidromeChecker Queue */ 6 | function palidromeCheckerUsingQueue (string) { 7 | let lowerCaseString = string.toLocaleLowerCase().split(' ').join(""); 8 | let queue = new Queue() 9 | for (let index = string.length; index >= 0 ; index--) { 10 | queue.equeue(lowerCaseString.charAt(index)); 11 | } 12 | let reverseString = ""; 13 | while(!queue.isEmpty()){ 14 | reverseString += queue.dequeue(); 15 | } 16 | // console.log(reverseString); 17 | 18 | if (lowerCaseString == reverseString) { 19 | return true; 20 | } 21 | return false; 22 | 23 | } 24 | 25 | /* Using palidromeChecker Stack */ 26 | function palidromeCheckerUsingStackObject (string) { 27 | let lowerCaseString = string.toLocaleLowerCase().split(' ').join(""); 28 | let stack = new StackObject(); 29 | for (let index = 0 ; index < lowerCaseString.length; index++) { 30 | stack.push(lowerCaseString.charAt(index)); 31 | } 32 | let reverseString = ""; 33 | while(!stack.isEmpty()){ 34 | reverseString += stack.pop(); 35 | } 36 | // console.log(reverseString); 37 | 38 | if (lowerCaseString == reverseString) { 39 | return true; 40 | } 41 | return false; 42 | } 43 | /* Using palidromeChecker Stack */ 44 | function palidromeCheckerUsingStack (string) { 45 | let lowerCaseString = string.toLocaleLowerCase().split(' ').join(""); 46 | let stack = new Stack(); 47 | for (let index = 0 ; index < lowerCaseString.length; index++) { 48 | stack.push(lowerCaseString.charAt(index)); 49 | } 50 | 51 | let reverseString = ""; 52 | while(!stack.isEmpty()){ 53 | reverseString += stack.pop(); 54 | } 55 | // console.log(reverseString); 56 | 57 | if (lowerCaseString == reverseString) { 58 | return true; 59 | } 60 | return false; 61 | } 62 | 63 | function palidromeCheckerUsingDeque (string) { 64 | let lowerCaseString = string.toLocaleLowerCase().split(' ').join(""); 65 | let isEqual = true; 66 | let dequeue = new Dequeue(); 67 | for (let index = 0 ; index < lowerCaseString.length; index++) { 68 | dequeue.addBack(lowerCaseString.charAt(index)); 69 | } 70 | // console.log(dequeue.items); 71 | while(!dequeue.size() > 1 && isEqual){ 72 | let startChar = dequeue.removeFront(); 73 | let endChar = dequeue.removeBack(); 74 | // console.log(` ${startChar} || ${endChar}`); 75 | if (startChar != endChar) { 76 | isEqual = false; 77 | } 78 | } 79 | return isEqual; 80 | } 81 | 82 | console.log("Stack"); 83 | console.time(); 84 | console.log(palidromeCheckerUsingStack('madam tt madam ')); 85 | console.timeEnd(); 86 | console.log("============================================="); 87 | console.log("StackObject"); 88 | console.time(); 89 | console.log(palidromeCheckerUsingStackObject('madam tt madam ')); 90 | console.timeEnd(); 91 | console.log("============================================="); 92 | console.log("Queue"); 93 | console.time(); 94 | console.log(palidromeCheckerUsingQueue('madam tt madam ')); 95 | console.timeEnd(); 96 | console.log("============================================="); 97 | console.log("Dequeue"); 98 | console.time(); 99 | console.log(palidromeCheckerUsingDeque('madam tt madam ')); 100 | console.timeEnd(); 101 | console.log("============================================="); 102 | -------------------------------------------------------------------------------- /queue.md: -------------------------------------------------------------------------------- 1 | # Queue 2 | 3 | ## What is the Queue? 4 | 5 | > _A Queue is a linear structure which follows a particular order in which the operations are performed. The order is **FIFO**\(First In First Out\)_ -geeksforgeeks.org 6 | 7 | _A real-world example of a queue can be people standing at the bus stop where the first standing in the line will be the first person to get out of the line i.e. first in first out. If you compared it to a_ [_**stack**_](https://dev.to/swarup260/data-structures-algorithms-in-javascript-stack-1ilb)_, the last person will be the first to leave._ 8 | 9 | This article will go through a list of following Queue DS, 10 | 11 | * Queue. 12 | * Deque\(Double-ended queue\). 13 | 14 | ## List Of Operations Available 15 | 16 | * **Enqueue** : Insert an element at the end of the queue. 17 | * **Dequeue** : Remove an element from the front of the queue. 18 | * **Front** : Return the first element of the queue. 19 | * **Size** : Return Size of the queue. 20 | * **isEmpty** : Check if the queue is empty if empty return true else false. 21 | * **Clear** : Reset the queue. 22 | 23 | ### Implementation of Queue in Javascript 24 | 25 | let's define **ES6** class name _**Queue**_, with properties, _count_ which will keep track of the number of elements in the queue and _items_ object which will store the elements. since we will be removing elements from the front of the queue, we also need a variable to help us track the first element. For this purpose, we declare the _lowestCount_ variable 26 | 27 | ```javascript 28 | class Queue { 29 | constructor() { 30 | this.count = 0; 31 | this.lowestCount = 0; 32 | this.items = {}; 33 | } 34 | } 35 | ``` 36 | 37 | #### **Enqueue** 38 | 39 | Insert an element in the queue is same as the [push](https://dev.to/swarup260/data-structures-algorithms-in-javascript-stack-1ilb#push) method of the stack or as Array _push_ method. 40 | 41 | ```javascript 42 | enqueue(element){ 43 | this.items[this.count] = element; 44 | this.count ++; 45 | } 46 | ``` 47 | 48 | #### **Dequeue** 49 | 50 | To remove an element from the **Queue**, we first check if the Queue is empty if empty return _undefined_ else store the _lowestCount_ property element in a variable, To return the element after deletion, Delete the _lowestCount_ item & increment the count by one. Dequeue method is same as the Array _shift_ method which removes the first element. 51 | 52 | ```javascript 53 | dequeue(){ 54 | if (this.isEmpty()) { 55 | return undefined; 56 | } 57 | let result = this.items[this.lowestCount]; 58 | delete this.items[this.lowestCount]; 59 | this.lowestCount ++; 60 | return result; 61 | 62 | } 63 | ``` 64 | 65 | #### **Front** 66 | 67 | This method will return the item from the front of the queue \(using the _lowestCount_ as a key to retrieve the element value\) 68 | 69 | ```javascript 70 | front(){ 71 | if (this.isEmpty()) { 72 | return undefined; 73 | } 74 | return this.items[this.lowestCount]; 75 | 76 | } 77 | ``` 78 | 79 | #### **Size** 80 | 81 | This method will return the size of the queue which is _count_ minus the _lowestCount_. 82 | 83 | ```javascript 84 | size() { 85 | return this.count - this.lowestCount; 86 | } 87 | ``` 88 | 89 | Example:-In the below queue items object, If the zeroth element was removed from the front of the queue, the lowest count will be one. The total count of the element will be two, therefore, the size of the queue will count-lowest count 90 | 91 | ```javascript 92 | let queue = { 93 | 1: "1", 94 | 2: "2", 95 | } 96 | ``` 97 | 98 | #### **isEmpty** 99 | 100 | **isEmpty** will return true if the queue is empty. 101 | 102 | ```javascript 103 | isEmpty() { 104 | return this.size() === 0; 105 | } 106 | ``` 107 | 108 | #### **Clear** 109 | 110 | To **clear** all the elements from the queue, we can evoke the dequeue method until it returns undefined or we can simply reset the value of the Queue class properties to the same values as declared in its constructor 111 | 112 | ```javascript 113 | clear() { 114 | this.items = {} 115 | this.count = 0; 116 | this.lowestCount = 0; 117 | return this.items; 118 | } 119 | ``` 120 | 121 | you get the full source [here](https://github.com/swarup260/Learning_Algorithms/blob/master/data_structure/Queue.js) 122 | 123 | ### Conclusion : 124 | 125 | | Methods | Complexity | 126 | | :--- | :---: | 127 | | equeue | O\(1\) | 128 | | dequeue | O\(1\) | 129 | | front | O\(1\) | 130 | | size | O\(1\) | 131 | 132 | -------------------------------------------------------------------------------- /set.md: -------------------------------------------------------------------------------- 1 | # Set 2 | 3 | ## What is Set? 4 | 5 | > _Sets are a type of associative containers in which each element has to be unique because the value of the element identifies it. The value of the element cannot be modified once it is added to the set, though it is possible to remove and add the modified value of that element_ - [_geeksforgeeks_](https://www.geeksforgeeks.org/) 6 | 7 | ### List Of Operations Available 8 | 9 | * **Add**: Insert an element in the set if present not. 10 | * **Delete**: Remove an element from the set. 11 | * **Has** : Return _true_ if the an element is present or else return _false_. 12 | * **Size**: Return Size of the Set. 13 | * **isEmpty** : Check if the set is empty if empty return true else false. 14 | * **Union**: Return new Set which contains all the elements from two sets. 15 | * **Intersection**: Return new Set which contains the intersecting element from two sets. 16 | * **Difference**: Return new Set only containing the elements which are not present in other sets. 17 | * **isSubset**: Return true if all elements are present in the given otherSet. 18 | 19 | > **Set Only Contains Unique Elements in it.** 20 | 21 | #### Implementation of Set in Javascript 22 | 23 | Let start by defining an [ES6 class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) class name **Set** that has one property, _items_ which will hold the elements in the set.we are using objects to store elements in the set instead, you can also use an array. 24 | 25 | ```javascript 26 | class Set { 27 | constructor() { 28 | this.items = {}; 29 | } 30 | } 31 | ``` 32 | 33 | ### Add 34 | 35 | While inserting an element into the Set, we first need to check if it already exists or not. By using **has** a method. 1. if the element is already present 36 | 37 | * Return false 38 | 1. Else insert an element into the Set. 39 | * Set items property key and value as an element. 40 | 41 | ```javascript 42 | add(element) { 43 | if (!this.has(element)) { 44 | this.items[element] = element; 45 | return true; 46 | } 47 | return false; 48 | } 49 | ``` 50 | 51 | ### Has 52 | 53 | Check if the element already exists in the set or not. You can loop until the entire the items and compare the given element with the set elements. _If a match is found then return **true** or else **false**._ Or you can javascript built-in method of [Object.prototype.hasOwnProperty\(\)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty) 54 | 55 | ```javascript 56 | has(element) { 57 | return Object.prototype.hasOwnProperty.call(this.items, 58 | element); 59 | } 60 | ``` 61 | 62 | ### Delete 63 | 64 | Remove an element from the set. 65 | 66 | * Check if the element is already present 67 | 68 | * If not present return **false**. 69 | * Else **delete** the element from the _items_ property. 70 | 71 | \`\`\`javascript 72 | 73 | delete\(element\) { if \(this.has\(element\)\) { delete this.items\[element\]; return true; } return false; } 74 | 75 | ```text 76 | ## Elements 77 | Return all elements present in the Set 78 | 79 | ```javascript 80 | elements(){ 81 | let elements = []; 82 | for (const key in this.items) { 83 | if (this.items.hasOwnProperty(key)) { 84 | elements.push(key); 85 | } 86 | } 87 | return elements; 88 | } 89 | ``` 90 | 91 | > **Set** Data Structure was also introduced in the ES6, javascript all the methods defined until know is present in Standard ES6 [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set). 92 | 93 | ## Set Operations 94 | 95 | In mathematics, a \[set\]\([https://en.wikipedia.org/wiki/Set\_\(mathematics](https://en.wikipedia.org/wiki/Set_%28mathematics)\)\) also has some basic operations such as _union_, _intersection_, and _difference_. 96 | 97 | ### Union 98 | 99 | The union of the sets A and B, denoted by **A ∪ B**. It is set only contains _distinct elements_ from set A or set B or both. 100 | 101 | ```text 102 | Eg :- 103 | 104 | Set A = {1,2,3,4,5,6} 105 | Set B = {3,4,5,10} 106 | 107 | A ∪ B = { 1,2,3,4,5,6,10 } 108 | ``` 109 | 110 | ![Set Operation Union](https://dev-to-uploads.s3.amazonaws.com/i/wav5nevjooxh1ouitx39.png) 111 | 112 | * otherSet Must be an Instance of Set if not throw an error. 113 | * Define a new Union Set. 114 | * Loop both the Sets and add elements into the Union Set if not present. 115 | 116 | ```javascript 117 | union(otherSet){ 118 | if (!(otherSet instanceof Set)) { 119 | throw new Error("Must be Instance Of Set"); 120 | } 121 | const unionSet = new Set(); 122 | this.elements().forEach(element => { 123 | unionSet.add(element); 124 | }); 125 | otherSet.elements().forEach(element => { 126 | unionSet.add(element); 127 | }); 128 | 129 | return unionSet; 130 | 131 | } 132 | ``` 133 | 134 | ### Intersection 135 | 136 | The intersection of the sets A and B, denoted by **A ∩ B**, is the Set of elements belongs to both A and B, only _common elements_. 137 | 138 | ```text 139 | Eg :- 140 | 141 | Set A = {1,2,3,4,5,6} 142 | Set B = {3,4,5,10} 143 | 144 | A ∩ B = {3,4,5 } 145 | ``` 146 | 147 | ![Set Operation Intersection](https://dev-to-uploads.s3.amazonaws.com/i/ywj3tme2dnq04a2kjd8k.jpg) 148 | 149 | * otherSet Must be an Instance of Set if not throw an error. 150 | * Define a new Intersection Set. 151 | * Loop the Set and add elements into the Intersection Set if and only if, the elements are present in both the Sets. 152 | 153 | ```javascript 154 | intersection(otherSet){ 155 | if (!(otherSet instanceof Set)) { 156 | throw new Error("Must be Instance Of Set"); 157 | } 158 | const intersectionSet = new Set(); 159 | this.elements().forEach(element => { 160 | if (otherSet.has(element)) { 161 | intersectionSet.add(element); 162 | } 163 | }); 164 | 165 | return intersectionSet; 166 | } 167 | ``` 168 | 169 | ### Difference 170 | 171 | The difference between sets A and B is denoted by **A – B**. Only containing _elements of set A but not in B_. 172 | 173 | ```text 174 | Eg :- 175 | 176 | Set A = {1,2,3,4,5,6} 177 | Set B = {3,4,5,10} 178 | 179 | A – B = {1,2,6} 180 | ``` 181 | 182 | ![Set Operation Difference](https://dev-to-uploads.s3.amazonaws.com/i/awhve9zscudal5fjun2u.png) 183 | 184 | * otherSet Must be an Instance of Set if not throw an error. 185 | * Define a new Difference Set. 186 | * Loop the Set and add elements into the Difference Set which are not common in otherSet 187 | 188 | ```javascript 189 | difference(otherSet){ 190 | if (!(otherSet instanceof Set)) { 191 | throw new Error("Must be Instance Of Set"); 192 | } 193 | const differenceSet = new Set(); 194 | this.elements().forEach(element => { 195 | if (!otherSet.has(element)) { 196 | differenceSet.add(element); 197 | } 198 | }); 199 | return differenceSet; 200 | } 201 | ``` 202 | 203 | ### isSubset 204 | 205 | A is a subset of B, denoted by **A ⊆ B** or equivalently.if only if all the _elements of A is present in B_. 206 | 207 | ![Set Operation isSubset](https://dev-to-uploads.s3.amazonaws.com/i/h2uuenvu080xfevo6va7.jpg) 208 | 209 | * otherSet Must be an Instance of Set if not throw an error. 210 | * Loop the otherSet check if all the elements are present or not or use [every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) method. 211 | 212 | ```javascript 213 | isSubset(otherSet){ 214 | if (!(otherSet instanceof Set)) { 215 | throw new Error("Must be Instance Of Set"); 216 | } 217 | if (!(otherSet.size() > this.size())) { 218 | return false; 219 | } 220 | let isSubset = true; 221 | this.elements().every(element => { 222 | if (!otherSet.has(element)) { 223 | isSubset = false; 224 | return; 225 | } 226 | }); 227 | 228 | return isSubset; 229 | 230 | } 231 | ``` 232 | 233 | you get the full source [here](https://github.com/swarup260/Learning_Algorithms/blob/master/data_structure/Set.js) 234 | 235 | #### Conclusion : 236 | 237 | | Methods | Complexity | 238 | | :--- | :---: | 239 | | Add | O\(n\) | 240 | | Delete | O\(1\) | 241 | | Has | O\(n\) | 242 | 243 | -------------------------------------------------------------------------------- /stack.md: -------------------------------------------------------------------------------- 1 | # Stack 2 | 3 | ## What is Stack? 4 | 5 | > _Stack is a linear data structure which follows a particular order in which the operations are performed. The order may be **LIFO**\(Last In First Out\) or **FILO**\(First In Last Out\)._ - geeksforgeeks.org 6 | 7 | _Real World eg. of the stack can be a pile of books, where books are placed one above another, books can be added or remove from the top of the pile of books_ 8 | 9 | ## List Of Operations Available 10 | 11 | * **Push** : Insert an element in the stack. 12 | * **Pop** : Remove an element in the stack. 13 | * **Peek** : Return the top element of the stack. 14 | * **Size** : Return Size of the stack. 15 | * **isEmpty** : Check if the stack is empty if empty return true else false. 16 | * **Clear** : Reset the stack. 17 | 18 | ## Implementation of Stack in Javascript 19 | 20 | There are two ways in which stack can implement in javascript one way by using Array or using javascript object\( object is a set of key & value\).As Array already have _push_ method to insert an element at end of the array, _pop_ method to remove an element, to get the length of the array it has a property _length_ which returns the size of the array if the length is equal to zero then the array is empty. you get the full source [here](https://github.com/swarup260/Learning_Algorithms/blob/master/data_structure/Stack.js) 21 | 22 | ### Implementation of Stack using Javascript Objects 23 | 24 | let's define **ES6 class** name Stack, with two properties, _count_ which will keep track of the number of elements in the stack and _items_ an object which will store the elements as value and count as key. 25 | 26 | ```javascript 27 | class Stack { 28 | constructor() { 29 | this.count = 0; 30 | this.items = {}; 31 | } 32 | } 33 | ``` 34 | 35 | #### **Push** 36 | 37 | To add an element to the stack we will use the count property as key for the _items_ object & element as values. After pushing the element in the stack we will increment the _count_ property by one.**we can only add new items to the top of the stack, meaning at the end of the stack** 38 | 39 | ```javascript 40 | push(element) { 41 | this.items[this.count] = element; 42 | this.count++; 43 | } 44 | ``` 45 | 46 | #### **Pop** 47 | 48 | While removing an element from the stack, there two cases: 1. If the stack is empty, return **undefined** 2. If the stack is not empty 49 | 50 | * Store the value of the top element i.e _\(count -1\)_ 51 | * decrease the _count_ property by one 52 | * delete element from _items_ object and return the stored value. 53 | 54 | **As the stack uses the LIFO principle, the last item that we added is the one that is removed** 55 | 56 | ```javascript 57 | pop() { 58 | if (this.isEmpty()) { 59 | return undefined; 60 | } 61 | let result = this.items[this.count-1]; 62 | this.count --; 63 | delete this.items[this.count]; 64 | 65 | return result; 66 | } 67 | ``` 68 | 69 | #### **Peek** 70 | 71 | If the stack is empty, return **undefined** else return the **Top**element i.e _\(count -1\)_ 72 | 73 | ```javascript 74 | peek() { 75 | 76 | if (this.isEmpty()) { 77 | return undefined; 78 | } 79 | return this.items[this.count-1]; 80 | } 81 | ``` 82 | 83 | #### **Size** 84 | 85 | Return _count_ property, which keeps track of the number of elements in the stack. 86 | 87 | ```javascript 88 | size() { 89 | return this.count; 90 | } 91 | ``` 92 | 93 | #### **isEmpty** & **Clear** 94 | 95 | isEmpty return **boolean value**, if the _count_ property is zero then true else false. And to clear the stack, we can simply reset it to the same values we used in the constructor. 96 | 97 | ```javascript 98 | isEmpty() { 99 | return this.count == 0; 100 | } 101 | 102 | clear() { 103 | this.items = {}; 104 | this.count = 0; 105 | return this.items; 106 | } 107 | ``` 108 | 109 | We could also use the following logic to remove all elements from the stack, respecting the LIFO behavior: 110 | 111 | ```javascript 112 | while (!this.isEmpty()) { 113 | this.pop(); 114 | } 115 | ``` 116 | 117 | you get the full source [here](https://github.com/swarup260/Learning_Algorithms/blob/master/data_structure/Stack.js) 118 | 119 | ### Conclusion : 120 | 121 | Stacks have a variety of applications in real-world problems. They can be used for backtracking problems to remember tasks or paths visited, and to undo actions. Complexity of stack is methods as follows. 122 | 123 | | Methods | Complexity | 124 | | :--- | :---: | 125 | | pop | O\(1\) | 126 | | push | O\(1\) | 127 | | peek | O\(1\) | 128 | 129 | -------------------------------------------------------------------------------- /tests/LinkedListTest.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var expect = require('expect.js'); 3 | const { LinkedList } = require('../data_structure/LinkedList'); 4 | 5 | describe("Linked List " ,function(){ 6 | const linkedList = new LinkedList(); 7 | it('Must Be Instance of LinkedList', function () { 8 | assert.equal(linkedList instanceof LinkedList, true); 9 | }); 10 | it("Head Must be undefined",function(){ 11 | assert.equal(linkedList.head, undefined); 12 | }); 13 | 14 | it("Head Must be 'swarup'",function(){ 15 | linkedList.push("swarup"); 16 | assert.equal(linkedList.head.element, "swarup"); 17 | }); 18 | it("Head Must be 'swarup'",function(){ 19 | linkedList.push("mallika"); 20 | assert.equal(linkedList.head.element, "swarup"); 21 | }); 22 | it("Head Must be 'papa' since the element was insert at '0' index",function(){ 23 | linkedList.insert("papa",0); 24 | assert.equal(linkedList.head.element, "papa"); 25 | }); 26 | it("Linked list size must be equal to 3",function(){ 27 | assert.equal(linkedList.size(), 3); 28 | }); 29 | 30 | it("Linked List ToString must be equal to 'papa, swarup, mallika'",function(){ 31 | assert.equal(linkedList.toString(), "papa, swarup, mallika"); 32 | }); 33 | it("Linked List ToArray '['papa', 'swarup', 'mallika']'",function(){ 34 | // expect([1, 2, 3]).to.eql([1, 2, 3]); // passes 35 | expect(linkedList.toArray()).to.eql(["papa", "swarup", "mallika"]); 36 | }); 37 | 38 | }) -------------------------------------------------------------------------------- /tests/QueueTest.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | const { Queue } = require('../data_structure/Queue'); 3 | 4 | describe("Queue", function () { 5 | const queue = new Queue(); 6 | it('Must Be Instance of Queue', function () { 7 | assert.equal(queue instanceof Queue, true); 8 | }); 9 | it('Equeue an element from queue', function () { 10 | queue.equeue("Swarup"); 11 | assert.equal(queue.size(),1); 12 | }); 13 | it('Dqueue an element from queue', function () { 14 | queue.dequeue("Swarup"); 15 | assert.equal(queue.size(),0); 16 | }); 17 | it('Queue size must be 2', function () { 18 | queue.equeue("Swarup"); 19 | queue.equeue("Roshan"); 20 | assert.equal(queue.size(),2); 21 | }); 22 | it('Peek element will be "Swarup" since its first element of the queue', function () { 23 | queue.equeue("Shreyash"); 24 | assert.equal(queue.peek(),"Swarup"); 25 | }); 26 | }) -------------------------------------------------------------------------------- /tests/SetTest.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | const { Set } = require('../data_structure/Set'); 3 | 4 | describe("Set", function () { 5 | const set = new Set(); 6 | it('Must Be Instance of Set', function () { 7 | assert.equal(set instanceof Set, true); 8 | }); 9 | it('Add Element in Set and Length Must be One', function () { 10 | set.add("Swarup"); 11 | assert.equal(set.size(), 1); 12 | }); 13 | 14 | it('Add Duplicate Element in Set and Length Must be One', function () { 15 | set.add("Swarup"); 16 | assert.equal(set.size(), 1); 17 | }); 18 | it('Remove Element from Set and set must be empty as no. element was one', function () { 19 | set.delete("swarup"); 20 | assert.equal(set.size(), 0); 21 | // assert.equal(set.isEmpty(), true); 22 | }); 23 | 24 | }); -------------------------------------------------------------------------------- /tests/StackTest.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | const { 3 | StackObject 4 | } = require('../data_structure/Stack') 5 | 6 | describe('Stack', function () { 7 | const stack = new StackObject(); 8 | it('Must Be Instance of Stack Object', function () { 9 | assert.equal(stack instanceof StackObject, true); 10 | }); 11 | it('Push An Element to Stack And Length must be One', function () { 12 | stack.push("Swarup") 13 | assert.equal(stack.size(), 1); 14 | }); 15 | it('Peek Element Must "Swarup" As its the top element of the stack', function () { 16 | assert.equal(stack.peek(), "Swarup"); 17 | }); 18 | it('After Clear the Stack Must be Empty', function () { 19 | stack.clear(); 20 | assert.equal(stack.size(), 0); 21 | }); 22 | 23 | }); -------------------------------------------------------------------------------- /utils/function.js: -------------------------------------------------------------------------------- 1 | function toStringFunc(key) { 2 | if (key == null) { 3 | return 'NULL' 4 | } 5 | if (key == undefined) { 6 | return 'UNDEFINED' 7 | } 8 | if ((typeof key == "string") || key instanceof String) { 9 | return `${key}`; 10 | } 11 | return key.toString(); 12 | } 13 | 14 | 15 | const Compare = { 16 | EQUALS: 0, 17 | LESS_THAN: -1, 18 | BIGGER_THAN: 1 19 | }; 20 | /** 21 | * 22 | * @param {*} a 23 | * @param {*} b 24 | * @returns {Compare} 25 | */ 26 | function defaultCompare(a, b) { 27 | if (a === b) { // {1} 28 | return Compare.EQUALS; 29 | } 30 | return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN; // {2} 31 | } 32 | 33 | /** 34 | * 35 | * @param {Array} array 36 | * @param {Number} index 37 | * @param {Number} nextIndex 38 | */ 39 | const swap = (array, index, nextIndex) => { 40 | [array[index], array[nextIndex]] = [array[nextIndex], array[index]]; 41 | } 42 | 43 | const defaultEqualFun = (a, b) => a == b; 44 | 45 | 46 | const diffFn = (a, b) => a - b; 47 | 48 | const lessOrEquals = (left, right, compareFun) => { 49 | const cmp = compareFun(left, right); 50 | return cmp == Compare.LESS_THAN || cmp == Compare.EQUALS; 51 | } 52 | 53 | const biggerOrEquals = (left, right, compareFun) => { 54 | const cmp = compareFun(left, right); 55 | return cmp == Compare.BIGGER_THAN || cmp == Compare.EQUALS; 56 | } 57 | 58 | 59 | 60 | 61 | module.exports = { 62 | toStringFunc, 63 | defaultCompare, 64 | Compare, 65 | swap, 66 | defaultEqualFun, 67 | lessOrEquals, 68 | biggerOrEquals, 69 | diffFn 70 | } --------------------------------------------------------------------------------