Notes on javascript data structure learning

Keywords: Javascript network

data structure

array

Method

//I. array
var arr = [];
// Additive elements
arr.push(1, 2); // [1,2]
// Insert first
arr.unshift(0); // [0, 1, 3]
// Tail deletion
arr.pop(); // [0, 1] 
// Head deletion
arr.shift(); // [1]
// Array merging
[1].concat([2]) // [1,2]

iterator

  • every every method iterates over each element in the array until it returns false.
  • Some is similar to each other, but some iterates over each element of the array until the function returns true
  • The results of forEach and for loops are the same
  • Map returns a new array [1,2]. map (o = > o * 2) / [2,4]
  • Filter returns a new array [1,2]. filter (o = O > O > 1) / [2]
  • reduce [1,2].reduce((result, current) => result + current) // 3
  • for of for (let n of numbers) { console.log((n % 2 === 0) ? 'even' : 'odd')};
  • entries

    const numbers = [1,2,3];
    let aEntries = numbers.entries(); // Iterator for Getting Key-Value Pairs
    console.log(aEntries.next().value); // The value of position 0 at [0, 1] is 1
    console.log(aEntries.next().value); // The value of [1, 2] position 1 is 2
    console.log(aEntries.next().value); // The value of [2, 3] position 2 is 3
  • keys

    const numbers = [1,2,3];
    console.log(Object.keys(numbers)); // ['0','1','2'];
  • values

    const numbers = [1,2,3];
    console.log(Object.values(numbers)); // [1,2,3]
  • Array.from
  • Array.of
  • fill
  • copyWithin
  • sort
  • find
  • findIndex
  • includes

Stack

A stack is an ordered set that follows the principle of last-in, first-out.

Realization

function Stack() {
    let items = [];
    // Adding elements to the stack
    this.push = function(element) {
        items.push(element);
    }
    // Remove elements from stack
    this.pop = function() {
        return items.pop();
    };
    // View stack top elements
    this.peek = function() {
        return items[item.length - 1];
    }
    // Check if the stack is empty
    this.isEmpty = function() {
        return items.length == 0;
    }
    this.size = function() {
        return items.length;
    };
    // Empty and print stack elements
    this.clear = function() {
        items = [];
    };
    this.print = function() {
        console.log(items.toString());
    };
}

Using stack to solve problems

Store accessed tasks or paths, undo operations, etc.

queue

The queue follows FIFO(First In First Out), also known as First In First Out (FIFO).

Realization

function Queue() {
    let items = [];
    // Adding elements to the queue
    this.enqueue = function(element) {
        items.push(element);
    };
    // Remove elements from queues
    this.dequeue = function() {
        return items.shift();
    };
    // View Queue Header Elements
    this.front = function() {
        return items[0];
    };
    // Check if the queue is empty
    this.isEmpty = function() {
        return items.length == 0;
    };
    this.size = function() {
        return items.length;
    };
    // Print queue elements
    this.print = function() {
        console.log(items.toString());
    };
}

linked list

A rough and orderly set of elements in a list village, but unlike arrays, elements in a list are not placed continuously in memory. Each element consists of a node that stores the element itself and a reference to the next element (also known as a pointer or link).
One advantage of linked lists over traditional arrays is that no other elements need to be moved when adding or removing elements. However, linked lists require pointers, so extra attention is needed to implement linked lists. Another detail of the array is that you can access any element directly anywhere, and to access an element in the middle of the list, you need to iterate through the list from the start (the header) until you find the required element.

Realization

function LinkedList() {
    let Node = function(element) {
        this.element = element;
        this.next = null;
    };

    let length = 0;
    let head = null;
    // Adding elements to the end of the list
    this.append = function(element) {
        let node = new Node(element),
        current;

        if (head === null) {
            head = node;
        } else {
            current = head;
            // Loop through the list until you find the last item
            while (current.next) {
                current = current.next;
            }
            // Find the last item, assign its next to a node, and establish a link
            current.next = node;
        }
        length++; // Length of update list
    }
    // Remove elements from the list
    this.removeAt = function() {
        // Check the crossover value
        if (position > -1 && position < length) {
            let current = head,
            previous,
            index = 0;

            // Remove the first item
            if (position === 0) {
                head = current.next;
            } else {
                while (index++ < position) {
                    previous = current;
                    current = current.next;
                }
                // Link previous to the next item of current: skip current and remove it
                previous.next = current.next;
            }
            length--;
            return current.element;
        } else {
            return null;
        }
    }
    // Insert elements anywhere
    this.insert = function(position, element) {
        // Check the crossover value
        if (position >= 0 && position <= length) {
            let node = new Node(element),
            current = head,
            previous,
            index = 0;

            if (position === 0) { // Add in the first place
                node.next = current;
                head = node;
            } else {
                while (index++ < position) {
                    previous = current;
                    current = current.next;
                }
                node.next = current;
                previous.next = node;
            }
            length++; // Length of update list
            return true;
        } else {
            return false;
        }
    }
    // toString method
    this.toString = function() {
        let current = head,
        string = '';

        while (current) {
            string += current.element + (current.next ? 'n' : '');
            current = current.next;
        }
        
        return string;
    }
    // indexOf method
    this.indexOf = function(elment) {
        let current = head,
        index = 0;
        
        while(current) {
            if (element === current.element) {
                return index;
            }
            index++;
            current = current.next;
        }

        return -1;
    }
    // Remote method
    this.remove = function(elment) {
        let index = this.indexOf(element);
        return this.removeAt(index);
    }
    // isEmpty method
    this.isEmpty = function() {
        return length == 0;
    }
    // size method
    this.size = function() {
        return length;
    }
    // getHead method
    this.getHead = function() {
        return head;
    }
}

Two-way Link List (for your own reflection)

aggregate

Sets are composed of a set of disorderly and unique (i.e., non-repeatable) items. This data structure uses the same mathematical concepts as the finite set, but it is applied in the data structure of computer science.

function Set() {
    let items = {};
    // has method
    this.has = function(value) {
        return items.hasOwnProperty(value);
    };
    // add method
    this.add = function(value) {
        if (!this.has(value)) {
            items[value] = value;
            return true;
        }
        return false;
    }
    // Remote method
    this.remove = function(value) {
        if (this.has(value)) {
            delete items[value];
            return true;
        }
        return false;
    }
    // clear method
    this.clear = function() {
        items = {};
    }
    // size method
    this.size = function() {
        return Object.keys(items).length;
    }
    // values method
    this.values = function() {
        let values = [];
        for (let i = 0, keys = Object.keys(items); i< keys.length; i++) {
            values.push(items[keys[i]]);
        }
        return values;
    }
    // Union
    this.union = function(otherSet) {
        let unionSet = new Set();

        let values = this.values();
        for (let i = 0; i < values.length; i++) {
            unionSet.add(values[i]);
        }

        values = otherSet.values();
        for (let i = 0; i < values.length; i++) {
            unionSet.add(values[i]);
        }

        return unionSet;
    }
    // intersection
    this.intersection = function(otherSet) {
        let intersectionSet = new Set();

        let values = this.values();
        for (let i = 0;i<values.length; i++) {
            if (otherSet.has(values[i])) {
                intersectionSet.add(values[i]);
            }
        }

        return intersectionSet;
    }
    // Difference set
    this.difference = function(otherSet) {
        let differenceSet = new Set();

        let values = this.values();
        for (let i = 0; i< values.length; i++) {
            if (!otherSet.has(values[i])) {
                differenceSet.add(values[i]);
            }
        }

        return differenceSet;
    }
    // subset
    this.subset = function(otherSet) {
        if (this.size() > otherSet.size()) {
            return false;
        } else {
            let values = this.values();
            for (let i = 0;i< values.length;i++) {
                if (!otherSet.has(values[i])) {
                    return false;
                }
            }
            return true;
        }
    }
}

Dictionaries and hash tables

Realization

function Dictionary() {
    var items = {};
    // has and set methods
    this.has = function(key) {
        return items.hasOwnProperty(key);
    }
    this.set = function(key, value) {
        item[key] = value;
    }
    // delete method
    this.delete = function(key) {
        if (this.has(key)) {
            delete items[key];
            return true;
        }
        return false;
    }
    // get and values methods
    this.get = function(key) {
        return this.has(key) ? items[key] : undefined;
    }
    this.values = function() {
        var values = [];
        for(var k in items) {
            if (this.has(k)) {
                values.push(items[k]);
            }
        }

        return values;
    }
    // clear method
    this.clear = function() {
        items = {};
    }
    // size method
    this.size = function() {
        return Object.keys(items).length;
    }
    // keys method
    this.keys = function() {
        return Object.keys(items);
    }
    // getItems method
    this.getItems = function() {
        return items;
    }

}

Hash table

The HashTable class, also known as the HashMap class, is a hash table implementation of the Dictionary class.
The purpose of hashing algorithm is to find a value in the data structure as quickly as possible.

function HashTable() {
    var table = [];
    var loseloseHashCode = function(key) {
        var hash = 0;
        for (var i = 0; i< key.length; i++) {
            hash += key.charCodeAt(i);
        }
        return hash % 37;
    }
    this.put = function(key, value) {
        var position = loseloseHashCode(key);
        console.log(position + ' - ' + key);
        table[position] = value;
    }
    this.get = function(key) {
        return table[loseloseHashCode(key)];
    }
    this.remove = function(key) {
        table[loseloseHashCode(key)] = undefined;
    }
}

Class Map

Adding Map Class to es6

var map = new Map();

map.set('a', 'b');

console.log(map.has('a')); // true
console.log(map.size()); // Output 1
console.log(map.keys()); // ['a']
console.log(map.values()); // ['b'];

// Unlike the Dictionary class, the values and keys methods of the Map class of es6 return Iterator instead of an array of values or keys.

ES6 - - WeakMap class and WeakSet class

  • WeakMap and WeakSet classes do not have entries keys values and other methods
  • Only objects can be used as keys
var map = new WeakMap();
var obj = {name: 'a'};
map.set(obj, 'b');

console.log(map.has(obj)); // Output true
console.log(map.get(obj)); // Input'b'
map.delete(obj);

tree

A tree structure consists of a series of nodes with parent-child relationship. Each node has a parent (except the first node at the top) and zero or more children.

Binary Tree and Binary Search Tree

function BinarySearchTree() {
    var Node = function(key) {
        this.key = key;
        this.left = null;
        this.right = null;
    }

    var root = null;

    var insertNode = function(node, newNode) {
        if (newNode.key < node.key) {
            if (node.left === null) {
                node.left = newNode;
            } else {
                insertNode(node.left, newNode);
            }
        } else {
            if (node.right === null) {
                node.right = newNode;
            } else {
                insertNode(node.right, newNode);
            }
        }
    }
    // Insert a key into the tree
    this.insert = function(key) {
        var newNode = new Node(key);

        if (root = null) {
            root = newNode;
        } else {
            insertNode(root, newNode);
        }
    }

    var inOrderTraverseNode = function(node, callback) {
        if (node !== null) {
            inOrderTraverseNode(node.left, callback);
            callback(node.key);
            inOrderTraverseNode(node.right, callback);
        }
    }

    // Sequential traversal
    this.inOrderTraverse = function(callback) {
        inOrderTraverseNode(root, callback);
    }

    var preOrderTraverseNode = function(node, callback) {
        if (node !== null) {
            callback(node.key);
            preOrderTraverseNode(node.left, callback);
            preOrderTraverseNode(node.right, callback);
        }
    }

    // Preorder traversal
    this.preOrderTraverse = function(callback) {
        preOrderTraverseNode(root, callback);
    }

    var postOrderTraverseNode = function(node, callback) {
        if (node !== null) {
            postOrderTraverseNode(node.left, callback);
            postOrderTraverseNode(node.right, callback);
            callback(node.key);
        }
    }

    // Post order traversal
    this.postOrderTraverse = function(callback) {
        postOrderTraverseNode(root, callback);
    }

    // Search for Minimum Value
    this.min = function() {
        return minNode(root);
    }

    var minNode = function(node) {
        if (node) {
            while( node && node.left !== null) {
                node = node.left;
            }
            return node.key;
        }
        return null;
    }

    // Search for maximum
    this.max = function() {
        return maxNode(root);
    }

    var maxNode = function(node) {
        if (node) {
            while(node && node.right !== null) {
                node = node.right;
            }
            return node.key;
        }
        return null;
    }

    // Search for a specific value
    this.search = function(key) {
        return searchNode(root, key);
    }

    var searchNode = function(node, key) {
        if (node === null) {
            return false;
        }
        if (key < node.key) {
            return searchNode(node.left, key);
        } else if (key > node.key) {
            return searchNode(node.right, key);
        } else {
            return true;
        }
    }

    // Remove a node
    this.remove = function(key) {
        root = removeNode(root, key);
    }

    var removeNode = function(node, key) {
        if (node === null) {
            return null;
        }
        if (key < node.key) {
            node.left = removeNode(node.left,key);
            return node;
        } else if (key > node.key) {
            node.right = removeNode(node.right,key);
            return node;
        } else { // Key equals node.key
            // The first case -- a leaf node
            if (node.left === null && node.right === null) {
                node = null;
                return node;
            }

            // The second case -- a node with only one child node
            if (node.left === null) {
                node = node.right;
                return node;
            } else if (node.right === null) {
                node = node.left;
                return node;
            }

            // The third case - a node with two subnodes
            var aux = findMinNode(node.right);
            node.key = aux.key;
            node.right = removeNode(node.rihgt, aux.key);
            return node;
        }

        var findMinNode = function(node) {
            while (node && node.left !== null) {
                node = node.left;
            }
            return node;
        }
    }
}

Self-balanced Tree (AVL)

When the tree is deep, adding removal and searching for a node causes some performance problems.

var heightNode = function(node) {
    if (node === null) {
        return -1;
    } else {
        return Math.max(heightNode(node.left), heightNode(node.right)) + 1;
    }
}

var rotationRR = function(node) {
    var tmp = node.right;
    node.right = tmp.left;
    tmp.left = node;
    return tmp;
}
var rotationLL = function(node) {
    var tmp = node.left;
    node.left = tmp.right;
    tmp.right = node;
    return tmp;
}

var rotationLR = function(node) {
    node.left = rotationRR(node.left);
    return rotationLL(node);
}

var rotationRL = function(node) {
    node.right = rotationLL(node.right);
    return rotationRR(node);
}

var insertNode = function(node, element) {
    if (node === null) {
        node = new Node(element);
    } else if (element < node.key) {
        node.left = insertNode(node.left, element);

        if (node.left !== null) {
            // Confirm whether there is a need for balance
            if ((heightNode(node.left) - heightNode(node.right) > 1)) {
                if (element < node.left.key) {
                    node = rotationLL(node);
                } else {
                    node = rotationLR(node);
                }
            }
        }
    } else if (element > node.key) {
        node.right = insertNode(node.right, element);

        if (node.right !== null) {
            // Confirm whether there is a need for balance
            if ((heightNode(node.right) - heightNode(node.left) > 1)) {
                if (element > node.right.key) {
                    node = rotationRR(node);
                } else {
                    node = rotationRL(node);
                }
            }
        }
    }
    return node;
}

chart

Graph is an abstract model of network structure. Graph is a group of nodes (or vertices) connected by edges. Learning graphs is important because any relationship can be represented by graphs.

function Graph() {
    var vertices = [];
    var adjList = new Dictionary();

    this.addVertex = function(v) {
        vartices.push(v);
        adjList.set(v, []);
    }

    this.addEdge = function(v, w) {
        addList.get(v).push(w);
        addList.get(w).push(v);
    }

    this.toString = function() {
        var s = '';
        for (var i = 0; i< vertices.length;i++) {
            s += vertices[i] + ' -> ';
            var neighbors = adjList.get(vertices[i]);
            for (var j = 0;j<neighbors.length;j++) {
                s += neighbors[j] + ' ';
            }
            s += '\n';
        }
        return s;
    }

    // Breadth-first search
    var initializeColor = function() {
        var color = [];
        for( var i = 0;i< vertices.length; i++) {
            color[vertices[i]] = 'white';
        }
        return color;
    }

    this.bfs = function(v, callback) {
        var color = initializeColor(),
        queue = new Queue();
        queue.enqueue(v);

        while(!queue.isEmpty()) {
            var u = queue.dequeue(),
            neighbors = adjList.get(u);
            color[u] = 'grey';
            for(var i = 0;i<neighbors.length;i++) {
                var w = neighbors[i];
                if (color[w] === 'white') {
                    color[w] = 'grey';
                    queue.enqueue(w);
                }
            }
            color[u] = 'black';
            if (callback) {
                callback();
            }
        }
    }

    // Using BFS to Find the Shortest Path
    this.BFS = function(v) {
        var color = initializeColor(),
        queue = new Queue(),
        d = [];
        pred = [];
        queue.enqueue(v);

        for( var i = 0;i< vertices.length;i++) {
            d[vertices[i]] = 0;
            pred[vertices[i]] = null;
        }

        while(!queue.isEmpty()) {
            var u = queue.dequeue(),
            neighbors = adjList.get(u);
            color[u] = 'grey';
            for( i = 0;i<neighbors.length;i++) {
                var w = neighbors[i];
                if (color[w] === 'white') {
                    color[w] = 'grey';
                    d[w] = d[u] + 1;
                    pred[w] = u;
                    queue.enqueue(w);
                }
            }
            color[u] = 'black';
        }
        return {
            distances: d,
            predecessors: pred
        }
    }

    // dfs
    var dfsVisit = function(u, color, callback) {
        color[u] = 'grey';
        if (callback) {
            callback(u);
        }
        var neighbors = adjList.get(u);
        for(var i = 0;i<neighbors.length;i++) {
            var w = neighbors[i];
            if (color[w] === 'white') {
                dfsVisit(w, color, callback);
            }
        }
        color[u] = 'black';
    }
    this.dfs = function(callback) {
        var color = initializeColor();

        for(var i = 0; i< vertices.length; i++) {
            if (color[vertices[i]] === 'white') {
                dfsVisit(vertices[i], color, callback);
            }
        }
    }

    // Exploring depth-first algorithm
    var time = 0;
    this.DFS = function() {
        var color = nitializeColor(),
        d = [],
        f = [],
        p = [],
        time = 0;

        for( var i = 0; i< vertices.length; i++) {
            f[vertices[i]] = 0;
            d[vertices[i]] = 0;
            p[vertices[i]] = null;
        }

        for (i = 0; i< vertices.length; i++) {
            if (color[vertices[i]] === 'white') {
                DFSVisit(vertices[i], color, d, f, p);
            }
        }

        return {
            discovery: d,
            finished: f,
            predecessors: p
        }
    }

    var DFSVisit = function(u, color, d, f, p) {
        console.log('discovered ' + u);
        color[u] = 'grey';
        d[u] = ++time;
        var neighbors = adjList.get(u);
        for(var i = 0;i<neighbors.length; i++) {
            var w = neighbors[i];
            if (color[w] === 'white') {
                p[w] = u;
                DFSVisit(w, color, d, f, p);
            }
        }
        color[u] = 'black';
        f[u] = ++time;
        console.log('explored ' + u);
    }
}

Posted by supernova on Sat, 18 May 2019 09:36:16 -0700