javascript-algorithms
Version:
algorithms for javascript
888 lines (762 loc) • 21.2 kB
JavaScript
/*
* a tree is nonlinear data structure
* trees are used to stroe hierarchical data(such as filesystem)
* you can search a binary tree very quickly
*
* ____
* ROOT ------> |____|
* /\
* / \
* __ __
* CHILD ------> |__||__|
* /
* /
* __
* |__|
*
* INSERT
* if value of new node is greater than its parent node,add it right branch else add it left brancsh
*
*
**/
(function (globals) {
function BinarySearchTree() {
this.baseNode = {
data: null,
right: null,
left: null
};
this.root = null;
this.insert = insertToBinarySearch;
this.inOrder = displayInOrder;
this.preOrder = displayPreOrder;
this.postOrder = displayPostOrder;
this.getMin = getMinOnBinarySearch;
this.getMax = getMaxOnBinarySearch;
this.find = findOnBinarySearch;
this.remove = removeOnBinarySearch;
this.removeNode = removeNodeOnBinarySearch;
}
function insertToBinarySearch(data, callback) {
var node = JSON.parse(JSON.stringify(this.baseNode));
node.data = data;
if (this.root == null) {
this.root = node;
} else {
var curr = this.root;
while (true) {
if (callback(curr.data, node.data)) {
if (curr.left == null) {
curr.left = node;
break;
} else {
curr = curr.left;
continue;
}
} else {
if (curr.right == null) {
curr.right = node;
break;
} else {
curr = curr.right;
continue;
}
}
}
}
return node;
}
function getMinOnBinarySearch() {
var curr = this.root;
var min = curr.data;
while (!(curr == null)) {
min = curr.data;
curr = curr.left;
}
return min;
}
function getMaxOnBinarySearch() {
var curr = this.root;
var max;
while (!(curr == null)) {
max = curr.data;
curr = curr.right;
}
return max;
}
function findOnBinarySearch(item, callback) {
var curr = this.root;
var parent;
while (callback(curr.data) != item) {
parent = curr;
if (callback(curr.data) > item) {
curr = curr.left;
} else {
curr = curr.right;
}
if (curr == null) {
return null;
}
}
return {parent: parent, current: curr};
}
function removeOnBinarySearch(data) {
var root = this.removeNode(this.root, data);
return root;
}
function removeNodeOnBinarySearch(node, data) {
if (node == null) {
return null;
}
if (node.data == data) {
if (node.left == null && node.right == null) {
return null;
}
//node has no left child
if (node.left == null) {
return node.right;
}
//node has no right child
if (node.right == null) {
return node.left;
}
//node has two child
var tempNode = getSmallest(node.right);
node.data = tempNode.data;
node.right = removeNodeOnBinarySearch(node.right, tempNode.data);
return node;
} else if (data < node.data) {
node.left = removeNodeOnBinarySearch(node.left, data);
return node;
} else if (data > node.data) {
removeNodeOnBinarySearch(node.right, data);
return node;
}
function getSmallest(n) {
if (n.left == null) {
return n;
} else {
getSmallest(n.left);
}
}
}
function displayInOrder(node) {
if (!(node == null)) {
displayInOrder(node.left);
process.stdout.write(node.data + " ");
displayInOrder(node.right);
}
}
function displayPreOrder(node) {
if (!(node == null)) {
process.stdout.write(node.data + " ");
displayPreOrder(node.left);
displayPreOrder(node.right);
}
}
function displayPostOrder(node) {
if (!(node == null)) {
displayPostOrder(node.left);
displayPostOrder(node.right);
process.stdout.write(node.data + " ");
}
}
/*
* thinking US state map;
* each town is connected with other town with roads
* a map is type of graph.
* each town is vertex and a road that connects two towns is a edge
* edges ==> (v1,v2) v1: town 1 and v2: town 2
* vertexs can also have a weight(cost)
* a path is squence of vertices in a graph
*
* One example is traffic flow. The vertices represent street intersections, and the edges represent the streets.
* Weighted edges can be used to represent speed limits or the number of lanes
*
* */
function Graph(v) {
this.adj = {};
this.visited = {};
this.edgeTo = [];
this.edges = 0;
this.addEdge = addEdge;
this.display = showGraph;
this.clearVisitedList = clearVisitedList;
this.depthFirstSearch = depthFirstSearch;
this.breadthFirstSearch = breadthFirstSearch;
this.dijkstra = dijkstra;
//this.pathTo = pathTo;
}
function addEdge(v1, v2, cost) {
//var edge = new Edge();
if (!this.adj.hasOwnProperty(v1)) {
this.adj[v1] = [];
this.visited[v1] = false;
}
if (!this.adj.hasOwnProperty(v2)) {
this.adj[v2] = [];
this.visited[v2] = false;
}
this.adj[v1].push({
to: v2,
cost: cost
});
this.adj[v2].push({
to: v1,
cost: cost
});
this.edges++;
}
function showGraph() {
for (var key in this.adj) {
process.stdout.write(key + "--> ");
for (var i = 0; i < this.adj[key].length; i++) {
process.stdout.write(this.adj[key][i].to + " ");
}
process.stdout.write("\n");
}
}
//GRAPH SEARCH
//depth-first search
//breadth-first search
function depthFirstSearch(v) {
if (this.adj.hasOwnProperty(v)) {
this.visited[v] = true;
}
for (var i = 0; i < this.adj[v].length; i++) {
if (this.visited[this.adj[v][i].to] == false) {
this.depthFirstSearch(this.adj[v][i].to);
}
}
}
function breadthFirstSearch(v) {
var queue = [];
//this.visited[v] = true;
queue.push(v);
while (queue.length > 0) {
var s = queue.shift();
if (this.visited[s] == false) {
this.visited[s] = true;
}
for (var i = 0; i < this.adj[s].length; i++) {
if (!this.visited[this.adj[s][i].to]) {
queue.push(this.adj[s][i].to);
this.edgeTo[this.adj[s][i].to] = s;
}
}
}
}
/*
function pathTo(target) {
var source = "a";
this.bfs(source);
var path = [];
for (var i = target; i != source; i = this.edgeTo[i]) {
path.push(i);
}
path.push(source);
return path.reverse();
}*/
function clearVisitedList() {
for (var key in this.visited) {
this.visited[key] = false;
}
}
function dijkstra(source, target) {
var dList = {};
var tempList = {};
var queue = [];
var paths = {};
var vCounter = 0;
queue.push(source);
for (var key in this.adj) {
dList[key] = Infinity;
paths[key] = []
}
while (queue.length > 0) {
var s = queue.shift();
if (this.visited[s] == false) {
vCounter++;
if (dList[s] == Infinity) {
dList[s] = 0;
paths[s].push(s);
}
this.visited[s] = true
}
for (var i = 0; i < this.adj[s].length; i++) {
queue.push(this.adj[s][i].to);
var totalCost = dList[s] + this.adj[s][i].cost;
if (totalCost < dList[this.adj[s][i].to]) {
paths[this.adj[s][i].to] = paths[s].slice();
paths[this.adj[s][i].to].push(this.adj[s][i].to);
dList[this.adj[s][i].to] = dList[s] + this.adj[s][i].cost;
tempList = dList;
}
}
if ((vCounter % 7 == 0) && (tempList == dList)) {
break;
}
}
return paths[target];
}
/**
*
* LINKED LIST
*
*/
function LinkedList() {
this.baseNode = {
element: null,
next: null
};
this.head = new Node("head");
this.current = this.head;
this.insert = insertToLinkedList;
this.remove = removeOnLinkedList;
this.find = findOnLinkedList;
this.display = showLinkedList();
}
function insertToLinkedList(newElement) {
var newNode = JSON.parse(JSON.stringify(newElement));
this.current.next = newNode;
newNode.next = null;
this.current = newNode;
};
function findOnLinkedList(callback) {
var currNode = this.head.next;
while (callback(currNode.element)) {
currNode = currNode.next;
}
return currNode;
};
function showLinkedList() {
var currNode = this.head;
do {
console.log(currNode.next.element);
currNode = currNode.next;
} while (currNode.next != null);
};
function removeOnLinkedList(callback) {
var currNode = this.head.next;
var prev = currNode;
while (!callback(currNode.element)) {
prev = currNode;
currNode = currNode.next;
}
prev.next = currNode.next;
return currNode;
};
/**
* Bubble Sort
* Selection Sort
* Insertion Sort
* --------------
* ShellSort
* MergeSort
* QuickSort
*/
function Sorting() {
this.CreateRandomArray = CreateRandomArray;
this.swap = swap;
this.bubbleSort = bubbleSort;
this.selectionSorting = selectionSorting;
this.shellSort = shellSort;
this.insertionSort = insertionSort;
this.mergeSort = mergeSort;
this.quickSort = quickSort;
}
function CreateRandomArray(size) {
var data = [];
for (var i = 0; i < size; i++) {
data[i] = Math.floor(Math.random() * (size * 20 + 1));
}
return data;
}
function swap(array, index1, index2) {
var temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
//one of the slowest sorting algorithms but easiest
function bubbleSort(arr, callback) {
for (var i = arr.length; i >= 2; --i) {
for (var j = 0; j < i - 1; ++j) {
if (callback(arr[j], arr[j + 1])) {
this.swap(arr, j, j + 1);
}
}
}
return arr;
}
function selectionSorting(arr, callback) {
for (var i = 0; i < arr.length - 1; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (callback(arr[i], arr[j])) {
this.swap(arr, i, j);
}
}
}
return arr;
}
function insertionSort(arr, callback) {
for (var i = 1; i < arr.length; i++) {
var temp = arr[i];
var j = i;
while (j > 0 && callback(arr[j - 1], temp)) {
arr[j] = arr[j - 1];
j = j - 1;
}
arr[j] = temp;
}
return arr;
}
function shellSort(arr, callback) {
var step = parseInt(arr.length / 2);
while (step > 0) {
for (var i = step; i < arr.length; i++) {
var k = arr[i];
for (var j = i; j >= step && callback(k, arr[j - step]); j -= step) {
arr[j] = arr[j - step];
}
arr[j] = k;
}
step = parseInt(step / 2);
}
return arr;
}
function mergeSort(arr, callback) {
var step = 1;
var left, right;
while (step < arr.length) {
left = 0;
right = step;
while (right + step <= arr.length) {
mergeArray(arr, left, left + step, right, right + step, callback);
left = right + step;
right = left + step;
}
if (right < arr.length) {
mergeArray(arr, left, left + step, right, arr.length, callback);
}
step *= 2;
}
function mergeArray(arr, startleft, stopleft, startright, stopright, callback) {
var leftArr = new Array(stopleft - startleft + 1);
var rightArr = new Array(stopright - startright + 1);
x = startleft;
for (var i = 0; i < (leftArr.length - 1); ++i) {
leftArr[i] = arr[x];
++x;
}
x = startright;
for (var i = 0; i < (rightArr.length - 1); ++i) {
rightArr[i] = arr[x];
++x;
}
leftArr[leftArr.length - 1] = Infinity;
rightArr[rightArr.length - 1] = Infinity;
var m = 0;
var n = 0;
var l;
var r;
for (var k = startleft; k < stopright; ++k) {
if (( (leftArr[m] == Infinity) ? Infinity : callback(leftArr[m]) )
<= ( (rightArr[n] == Infinity) ? Infinity : callback(rightArr[n]) )) {
arr[k] = leftArr[m];
m++;
}
else {
arr[k] = rightArr[n];
n++;
}
}
}
return arr;
}
function quickSort(arr, callback) {
if (arr.length == 0) {
return [];
}
var left = [];
var right = [];
var pivot = arr[0];
for (var i = 1; i < arr.length; i++) {
if (callback(arr[i], pivot)) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
var x = quickSort(left, callback).concat(pivot, quickSort(right, callback));
return x;
}
function DoublyLinkedList() {
this.baseNode = {
element: null,
next: null,
prev: null
};
this.head = new Node("head");
this.current = this.head;
this.insert = insertToDoublyLinkedList;
this.remove = removeOnDoublyLinkedList;
this.display = showDoublyLinkedList;
this.find = findOnDoublyLinkedList;
};
function insertToDoublyLinkedList(item) {
var newNode = JSON.parse(JSON.stringify(this.baseNode));
newNode.element = item;
this.current.next = newNode;
newNode.next = null;
newNode.prev = this.current;
this.current = newNode;
};
function findOnDoublyLinkedList(callback) {
var curr = this.head.next;
while (!callback(curr.element)) {
curr = curr.next;
}
return curr;
};
function removeOnDoublyLinkedList(callback) {
var willDelete = this.find(callback);
willDelete.prev.next = willDelete.next;
if (willDelete.next != null) {
willDelete.next.prev = willDelete.prev
}
return willDelete;
};
function showDoublyLinkedList() {
var curr = this.head.next;
while (curr != null) {
console.log(curr.element);
curr = curr.next;
}
}
/*
* hash table size is an important strategy
* sometimes size should be prime number
* and it is possible for two keys to hash
* to the same value.this is called collision
* important point is this situation!!
*
* Name | Hash Function | Hash Value | Hash Table
* ------ ------------------------------- ------------- ------------------------
* Durr | (68 + 117 + 114 + 114) | 413 | hash array[413] = Durr
* Smith | (83 + 109 + 105 + 116 + 104) | 517 | hash array[517] = Smith
*
*
*
* necessary due to the use of modular arithmatic in computing the key
* hash table size greater than 100 for evenly disperse the keys in hash table
* method for detect collision and resolve,it is seperate chaining
* Name | Hash Function | Hash Value | Hash Table
* ------ ------------------------------- ------------- ------------------------
* Durr | (68 + 117 + 114 + 114) | 413 | hash array[413] = [Durr,Durr]
* Smith | (83 + 109 + 105 + 116 + 104) | 517 | hash array[517] = [Smith]
*/
var HASH_TABLE_SIZE;
function HashTable(base) {
HASH_TABLE_SIZE = base.size;
this.table = new Array(HASH_TABLE_SIZE);
this.simpleHash = simpleHash;
this.display = showHashTable;
this.put = putToTable;
this.get = getFromTable;
this.buildChains = buildChains;
this.buildChains();
}
function putToTable(data) {
var address = this.simpleHash(data);
var find = false;
if (this.table[address][0] == undefined) {
this.table[address][0] = data;
} else {
for (var j = 1; j < this.table[address].length + 1; j++) {
if (this.table[address][j] == undefined) {
this.table[address][j] = data;
break;
}
}
}
};
function getFromTable(key) {
return this.table[this.simpleHash(key)];
}
function showHashTable() {
console.log("\033[31mAddress | \033[31mValue\x1b[0m");
console.log("----------- -----------");
for (var i = 0; i < HASH_TABLE_SIZE; i++) {
var val = this.table[i];
if (val.length != 0) {
process.stdout.write(i.toString());
for (var j = 0; j < 11 - i.toString().length; j++) {
process.stdout.write(" ");
}
process.stdout.write("| ");
for (var k = 0; k < val.length; k++) {
process.stdout.write(JSON.stringify(val[k]) + " ");
}
process.stdout.write("\n");
console.log("----------- -----------");
}
}
};
function buildChains() {
for (var i = 0; i < HASH_TABLE_SIZE; i++) {
this.table[i] = new Array();
}
};
function simpleHash(item) {
if (typeof item === 'string') {
return StringHash(item);
} else if (Object.prototype.toString.apply(item) === "[object Object]") {
return StringHash(JSON.stringify(item));
} else if (Object.prototype.toString.apply(item) === "[object Array]") {
///
return undefined
} else if (typeof item === 'number') {
return IntegerHash();
} else {
throw new TypeError("unexpected data type", "hashTable.js", 24);
}
};
function IntegerHash() {
var num = "";
for (var i = 1; i <= 9; i++) {
num += Math.floor(Math.random() * 10);
}
num += getRandomInt(50, 100);
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1));
};
return num;
};
function StringHash(item) {
var total = 0;
const H = 37;
for (var i = 0; i < item.length; i++) {
total += total * H + item.charCodeAt(i);
}
total = total % HASH_TABLE_SIZE;
if (total < 0) {
total += HASH_TABLE_SIZE - 1;
}
return parseInt(total);
}
/**
*
* HUFFMAN
*
*/
function Huffman(text) {
this.text = text;
this.coded = {};
this.node = {
right: null,
left: null,
freq: 0,
code: ""
};
this.encode = encode;
this.createHuffmanTree = createHuffmanTree;
this.sortByFrequency = sortByFrequency;
this.createFrequencyHash = createFrequencyHash;
this.createBitMap = createBitMap;
this.buildHuffmanCode = buildHuffmanCode;
}
function encode() {
this.textArray = this.text.split("");
var sortedHash = sortByFrequency(this.createFrequencyHash());
var tree = this.createHuffmanTree(sortedHash);
this.createBitMap(tree);
return this.buildHuffmanCode();
}
function decode(code){
}
function createHuffmanTree(elements) {
if (elements.length == 1)
return elements[0];
var parent = JSON.parse(JSON.stringify(this.node));
parent.left = elements[0];
parent.right = elements[1];
parent.freq = parent.left.freq + parent.right.freq;
elements.splice(0, 2);
elements.push(parent);
return this.createHuffmanTree(this.sortByFrequency(elements));
}
function sortByFrequency(hash) {
for (var i = 1; i < hash.length; i++) {
var temp = hash[i];
var j = i;
while (j > 0 && temp.freq < hash[j - 1].freq) {
hash[j] = hash[j - 1];
j--;
}
hash[j] = temp;
}
return hash;
}
function createFrequencyHash() {
var freq = [];
var found = false;
var index;
for (var i = 0; i < this.textArray.length; i++) {
for (var j = 0; j < freq.length; j++) {
if (freq[j].value == this.textArray[i]) {
found = true;
index = j;
}
}
if (found) {
freq[index].freq += 1;
found = false;
} else {
freq.push({value: this.textArray[i], freq: 1});
}
}
return freq;
}
function createBitMap(tree) {
if (!(tree == null) && (typeof tree !== 'undefined')) {
if (tree.left != null && (typeof tree.left !== 'undefined')) {
tree.left.code = tree.code + "0";
this.coded[tree.left.value] = tree.left.code;
}
if (tree.right != null && (typeof tree.right !== 'undefined')) {
tree.right.code = tree.code + "1";
this.coded[tree.right.value] = tree.right.code;
}
this.createBitMap(tree.left);
this.createBitMap(tree.right);
}
}
function buildHuffmanCode() {
for (var i = 0; i < this.textArray.length; i++) {
this.textArray[i] = this.coded[this.textArray[i]];
}
return this.textArray.join("");
}
var full = {
BinarySearchTree: BinarySearchTree,
Graph: Graph,
Sorting: Sorting,
Hash: HashTable,
DoublyLinkedList: DoublyLinkedList,
LinkedList: LinkedList,
Huffman: Huffman
};
if (typeof exports !== "undefined") {
if (typeof module !== "undefined" && module.exports) {
exports = module.exports = full;
}
exports.js_algorithms = full;
} else {
globals.js_algorithms = full;
}
if (typeof define === 'function' && define.amd) {
define('javascript-algorithms', [], function () {
return full;
});
}
})(this);