Data structure: JavaScript language description

list

When you don't need to find or sort elements in a long sequence.

Abstract data type definition of list

A list is an ordered set of data. (whether the data itself is in order or the index is in order)
Each data item in the list is called an element. Any data type can be in the list. The number of elements in the list is limited by the program memory.
A list that does not contain any elements is called an empty list.

attribute

length: number of list elements
listSize: the number of elements in the saved list

method

append(): you can add an element to the end of the list, or insert an element after a given element or at the beginning of the list
remove(): removes an element from the list.
clear(): clear all elements in the list.
toString(): displays all elements in the list.
getElement(): displays the current element.
The list has attributes that describe the location of the element. After the list has money.
next(): you can move from the current element to the next element.
prev(): you can move to the previous element of the current element.
moveTo(): move to the specified location
currPos(): current position in the list
end(): moves the current element to the last position
front(): move the current element to the first position

Implementation of list

function List() {
    this.dataStore = [];
    this.listSize = 0;
    this.pos = 0;
    this.length = this.dataStore.length;
}

List.prototype.append = function (element) {
    this.dataStore[this.listSize++] = element;
}
List.prototype.remove = function (element) {
    let result = this.dataStore.findIndex((ele)=>{
        return ele === element;
    });
   this.dataStore.splice(result, 1);
   this.listSize--;
   return 1;
}

List.prototype.find = function (element) {
    return this.dataStore.indexOf(element);
}

List.prototype.length = function () {
    return this.listSize;
}

List.prototype.toString = function () {
    return this.dataStore.toString();
}

// Insert an element after an element

List.prototype.insert = function (element, after) {
    let index = this.dataStore.findIndex((ele)=>{
        return ele === after
    });

    if(index > -1) {
        this.dataStore.splice(index + 1, 0 ,element);
        this.listSize++; 
        return true;
    }

    return false;
   
}   

List.prototype.clear = function () {
    delete this.dataStore;
    this.dataStore.length = 0;
    this.listSize = 0;
    this.pos = 0;
}

List.prototype.contains = function (element) {
    return this.dataStore.includes(element);
}

List.prototype.front = function () {
    this.pos = 0;
}

List.prototype.end = function () {
    this.pos = this.listSize-1;
}

List.prototype.getElement = function () {
    return this.dataStore[this.pos];
}

List.prototype.prev = function () {
    if(this.pos > 0){
        this.pos--;
    }
}

List.prototype.next = function () {
    if(this.pos < this.listSize-1){
        this.pos++;
    }
}
// Return to current position
List.prototype.currPos = function () {
    return this.pos;
}
// Move to the specified location
List.prototype.moveTo = function (index) {
    this.pos = index;
}

Traversing the list using iterators

Advantages of using iterators

  1. Don't care about the underlying data storage structure
  2. When inserting data into a list, only the list is updated, and the iterator does not need to be updated
  3. Iterators provide a unified way to access lists
// Traverse from front to back
for(list.front(); list.curPos() < list.length(); list.next()){
	console.log(list.getElement())
}

// Traverse from back to front
for(list.end(); list.curPos() >= 0; list.prev()){
	console.log(list.getElement());
}

Stack

Operation on stack

Stack is a special kind of list. The stack can only be at one end of the list, which is called the top of the stack. Data in the stack comes in first and then out.

attribute

Top: position of stack top
length: records the number of elements in the stack

method

push(): push into stack
pop(): pop up stack
peak(): returns the top element of the stack
clear(): clear all elements

Implementation of stack

function Stack() {
    this.stack = [];
    this.top = 0;
    this.length = 0;
}

Stack.prototype.push = function (element) {
    this.stack[this.top] = element;
    this.top++;
}

Stack.prototype.pop = function () {
    this.stack.splice(this.top - 1, 1);
    this.top--;
}

Stack.prototype.clear = function () {
  this.top = 0;
}

Stack.prototype.peak = function () {
    return this.stack[this.top - 1];
} 

Stack.prototype.length = function () {
    return this.top;
}

queue

A queue is a list. Pairs can only be inserted at the end of the queue and deleted at the head of the queue. Queues are used to store sequential data, first in, first out.

Operations on queues

The operation of inserting is called queuing, and the operation of deleting is called pairing.

method

peak(): read the element of the head of the queue
clear(): clear the queue
enquenen(): join the team
dequenen(): out of line
empty(): judge whether the queue is empty
front(): read the first element of the queue
end(): reads the last element of the queue

Implementation of queue

function Quenen() {
    this.dataStore = [];
    
}
// Join the team
Quenen.prototype.enquenen = function (element) {
    this.dataStore.push(element);

}
// Out of the team
Quenen.prototype.dequenen = function () {
    this.dataStore.shift();

}
// Clear queue
Quenen.prototype.clear = function () {
    this.dataStore = [];
}

Quenen.prototype.toString = function () {
    return this.dataStore.toString();
}
// Judge whether it is an empty pair of columns
Quenen.prototype.empty = function () {
    if(this.dataStore.length === 0){
        return true;
    } else {
        return false;
    }
}
// Returns the element at the head of the queue
Quenen.prototype.front = function () {
    return this.dataStore[0];
}
// Returns the element at the end of the queue
Quenen.prototype.end = function () {
    return this.dataStore[this.dataStore.length - 1];
}

Linked list

Disadvantages of arrays

  1. The length of the array is fixed, and it will be difficult to add when the array is filled
  2. Adding and deleting elements is troublesome. You need to move elements forward or backward
  3. Very slow

Define linked list

A linked list is a set of nodes. Each node uses a reference to an object to point to its successor, and a reference to another node is called a chain.
Array elements are referenced by their position, and linked lists are referenced by their relationship. The tail element of the linked list points to a null.
There is a head node at the front of the linked list.
Add element: the precursor of the current node points to the new node, and the new node points to the node to which the original precursor points.
Delete element: the precursor of the deleted element points to the node pointed by the deleted node, and the deleted node points to null.

operation

method

insert(): insert after a node
remove(): deletes a node according to its contents
findNode(): find a node according to its contents

Implementation of linked list

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

function LinkedList() {
    this.head = new Node('head');
}

LinkedList.prototype.findNode = function (element) {
    let head = this.head;
    while(head){
        if(head.element === element){
            return head.next;
        }
        head = head.next;
    }
    return head;
}

LinkedList.prototype.findPrevNode = function (element) {
    let head = this.head;
    let currentNode = this.findNode(element);
    while(head.next){
        if(head.next.element === currentNode.element){
            return head;
        }
    }
    return null;
}

// Insert after node
LinkedList.prototype.insert = function (element, afterElement) {
    let node = new Node(element);
// Find the node first
    let currentNode = this.findNode(afterElement);
    if(currentNode){
        if(currentNode.next){
            node.next = currentNode.next;
            currentNode.next = ndoe;
        } else {
            currentNode.next = node;
            node.next = null;
        }
    }
    
}

LinkedList.prototype.remove = function (element) {
    let currentNode = this.findNode(element);
    let prevNode = this.findPrevNode(element);
    if(prevNode){
        prevNode.next = currentNode.next;
        currentNode.next = null;
    }
}

Bidirectional linked list

function Node(element) {
    this.element = element;
    this.previous = null;
    this.next = null;
}
function LLinkedList(){
    this.head = new Node('head');
    this.next = null;
    this.previous = null;
}

LLinkedList.prototype.findNode = function (element) {
    let head = this.head;
    while(head){
        if(head.element === element){
            return head;
        }
        head = head.next;
    }
    return head;
}


LLinkedList.prototype.insert = function (element, afterElement) {
    let node = new Node(element);
    let currentNode = this.findNode(afterElement);
    if(currentNode){
        if(currentNode.next){
            node.previous = currentNode;
            node.next = node.previous.next;
            node.next.previous = node;
            node.previous.next = node;
        } else {
            node.next = null;
            node.previous = currentNode;
            currentNode.next = node;
        }
    }
   
}

LLinkedList.prototype.remove = function (element) {
    let currentNode = this.findNode(element);
    currentNode.previous.next = currentNode.next;
    currentNode.next.previous = currentNode.previous;
    currentNode.next = null;
    currentNode.previous = null;
}

Circular linked list

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

function CycleLinkedList() {
    this.head = new Node('head');
    this.head.next = this.head;
}

CycleLinkedList.prototype.findNode = function (element) {
    let head = this.head;
    while(head){
        if(head.element === element){
            return head;
        }
        head = head.next;
    }
    return head;
}

CycleLinkedList.prototype.insert = function (element, afterElement) {
    let node = new Node(element);
    let currentNode = this.findNode(afterElement);
    if(currentNode){
        if(currentNode.next){
            node.next = currentNode.next;
            currentNode.next = node;
        } else {
            currentNode.next = node;
            node.next = null;
        }
    }
}

Dictionaries

A dictionary is a data structure that stores data in the form of key value pairs. The dictionary class is based on the Array class, not the Object class.

Implementation of dictionary

function Dictionary()  {
    this.dataStore =  new Array();
}

Dictionary.prototype.add = function (key,value) {
    this.dataStore[key] = value;
}

Dictionary.prototype.find = function (key) {
    return this.dataStore[key];
}

Dictionary.prototype.remove = function (key) {
    delete this.dataStore[key];
}

Dictionary.prototype.showAll = function () {
    for(let key in Object.keys(this.dataStore).sort()){
        console.log(key + '->' + this.dataStore[key]);
    }
}

Dictionary.prototype.count = function () {
    let n = 0;
    for(let key in Object.keys(this.dataStore)){
        ++n;
    }
    return n;
}

hash

The hashed data can be accessed quickly. The data structure used for hashing is a hash table. Insertion, deletion and retrieval are fast, but search is slow.
When storing data through a hash table, the key is mapped to a number through the hash function, which ranges from 0 to the length of the hash table.
When two keys are mapped to a value, it is called collision.
The array length of hash table should be a prime number.

Select hash function

The choice of hash function depends on the data type of the key value. Division and remainder method. If the key type is a string, divide the sum of the ASCII values of each character by the remainder of the length of the array.

Collision handling

Open chain method

In the underlying array that implements the hash table, each element is another data structure

Linear detection method

In case of collision, detect whether the next position of the hash table is empty. If it is empty, store the data in the position. If it is not empty, continue to detect the next position until an empty position is found. When the array of stored data is very large, the linear detection method is better than the open chain method.
If the size of the array is 1.5 times the number of data to be stored, the open chain method is used; If the size of the array is twice or more than the number of data to be stored, linear detection method is used.

aggregate

A collection is a data structure that contains different elements. Elements in a collection are called members. The members in the collection are out of order. The same elements are not allowed in the collection.
A set is composed of a group of disordered but related members. Each member can only appear once in the set.

Definition of set

  • A set that does not contain any members is called an empty set, and a complete set is a set that contains all possible members.
  • If two sets have exactly the same members, they are said to be equal.
  • If all elements in one set are contained in another set, the former set is a subset of the latter set.

Operations on collections

  1. Union: merge the members of two sets to form a set
  2. Intersection: the common members in two sets form a new set
  3. Complementary set: a set of members belonging to one set but not to another

method

  • add: adds a member to the collection
  • remove: removes a member from the collection
  • show: displays the members in the collection

Implementation of set class

function Set(){
    this.dataStore = [];
    this.size = 0;
}

// Tool function
Set.prototype.indexOf = function (element) {
    return this.dataStore.indexOf(element);
} 

Set.prototype.add = function (element) {
    if(this.indexOf(element) !== -1){
        return false;
    } else {
        this.dataStore.push(element);
    }
}

Set.prototype.remove = function (element) {
    let index = this.indexOf(element);
    if(index !== -1){
        this.dataStore.splice(index, 1);
    } else {
        return false;
    }
}

Set.prototype.show = function () {
    return this.dataStore.toString();
}

// intersection
Set.prototype.union = function (set) {
    let unionSet = new Set();
    let tempStore = set.dataStore;
    for(let i = 0; i < this.dataStore.length; i++){
        unionSet.dataStore.concat(set.dataStore.filter((ele) => {
            return ele === this.dataStore[i];
        }));
    }
    return unionSet;
}

// Union
Set.prototype.interset = function (set) {
    let intersetSet = new Set();
    let tempStore = set.dataStore;
    for(let i = 0; i < this.dataStore.length; i++){
        tempStore = tempStore.filter((ele) => {
            return ele !== this.dataStore[i];
        });
    }

   intersetSet.dataStore = intersetSet.dataStore.concat(this.dataStore, tempStore);  
   return intersetSet;
}

// Complement
Set.prototype.diference = function (set){
    let difSet = new Set();
    for(let i = 0; i < this.dataStore.length; i++){
        if(set.dataStore.every((ele) => {
            return ele !== this.dataStore[i];
        })){
            difSet.dataStore.push(this.dataStore[i]);
        }
    }
    return difSet;
}

tree

Tree is a nonlinear retrieval data structure, which stores data in a hierarchical manner. Trees are used to store hierarchical data. Trees are also used to store sequence tables.

Definition of tree

A tree consists of nodes connected by edges. The top node of a tree becomes the root node. If a node connects multiple nodes, it is called the parent node, and the nodes below it become the child nodes. A node can have 0, 1 or more child nodes. Nodes without any child nodes become leaf nodes.
The number of child nodes of the node of the binary tree shall not exceed two. A set of edges from one node to another is called a path. Accessing all nodes in a particular order is called traversal of the tree. The tree can be divided into several levels. The root node is level 0. Any level node in the tree can be regarded as the root of the subtree. The number of layers of a tree is the depth of the tree. Each node has a value associated with it, usually a key.
The two nodes of a parent node become the left node and the right node respectively. In some binary tree implementations, the left node contains a specific set of values and the right node contains a specific set of values.
Binary lookup tree is a special binary tree. Its smaller value is placed in the left node and the larger value is saved in the right node.

Traversal of binary search tree

Middle order traversal

Access the nodes on the tree in ascending order according to the key values of the nodes.

Preorder traversal

First visit the root node, and then traverse the left and right subtrees in the same way.

Postorder traversal

First visit the leaf node, from the left subtree to the right subtree, and then to the root node.

Delete node

To delete a node, first judge whether the current node contains the data to be deleted. If so, delete the node; If not, compare the data of the current node with the data of the node to be deleted. If the data on the current node is less than the data of the node to be deleted, move to the left node of the current node to continue the comparison; If the data on the current node is larger than the data of the node to be deleted, move to the right node of the current node to continue the comparison.
If the deleted node is a leaf node, the link from the parent node to it points to null.
If the deleted node contains only one child node, the original link to it points to its child nodes.
If the deleted node contains two nodes, either find the maximum value of the left subtree of the node to be deleted or the minimum value of the right subtree of the node to be deleted.

chart

Definition of graph

A graph consists of a set of edges and a set of vertices. If the fixed-point pairs of a graph are ordered, it is called a directed graph. After sorting the vertex pairs of a directed graph, you can draw an arrow between the two vertices. A directed graph shows the flow direction of vertices.
If a graph is unordered, it is called an unordered graph or an undirected graph. A series of vertices in the graph form a path, and the vertices in the path are connected by edges. The length of the path is expressed by the number of edges from the first vertex to the last vertex.
A path consisting of vertices pointing to itself is called a ring, and the length of the ring is 0.
A circle is a path with at least one edge, and the first vertex of the path is the same as the last vertex. A circle without repeated vertices and edges is a simple circle. In addition to the first and last vertices, a circle with other repeated vertices in the path is called a trivial circle.
If there is path connectivity between two vertices, the two vertices are called strong connectivity.
If the vertices of a directed graph are strongly connected, then the graph is also strongly connected.

Modeling real systems with graphs

Represents an edge

We call the method of representing the edges of a graph adjacency table or adjacency table array. The edges are represented as an array of adjacent vertex lists with vertices, and the vertices are used as indexes.
Adjacency matrix is a two-dimensional array in which the elements indicate whether there is an edge between two vertices.
Use an array with the same length as the number of vertices to record the vertices, and create a sub array for each element to record the number of adjacent vertices.

function Map(v) {
    this.vertices = v;// Total number of nodes
    this.edges = 0;
    this.adj = [];
    this.edgeTo = [];
    this.marked = [];
    for(let i = 0; i < this.vertices; i++){
        this.adj[i] = [];
        this.adj[i].push('');
    }
    for(let i = 0; i < this.vertices; i++){
        this.marked[i] = false;
    }
    
}

Map.prototype.addEdge = function (v,w){
    this.adj[v].push(w);
    this.adj[w].push(v);
    this.edges++;
}

Map.prototype.show = function () {
    for(let i = 0; i < this.vertices; i++){
        for(let j = 0; j < this.vertices; j++){
            if(this.adj[i][j] !== undefined){
                console.log(this.adj[i][j])
            }
        }
    }
}
Map.prototype.pathTo = function (v) {
    var source = 0;
    if (!this.hasPathTo(v)) {
        return undefined;
    }
    var path = [];
    for (var i = v; i != source; i = this.edgeTo[i]) {
        path.push(i);
    }
    path.push(s);
    return path;
}
Map.prototype.hasPathTo =  function (v) {
     return this.marked[v];
}

Search graph

Those vertices can be reached from a specified vertex.

Depth first search

Start tracing from the starting vertex until the last vertex is reached, then trace back, start tracing the next path until the last vertex is reached, and so on until there is no path.

Map.prototype.dfs = function (v) {
    this.marked[v] = true;
    if(this.adj[v] !== undefined){
        for(let key in this.adj[v]){
            if(!this.marked[key]){
                this.dfs[key];
            }
        }
    }
}

Breadth first search

Starting with the first vertex, try to access the vertex as close to it as possible. First check the layer closest to the first vertex and gradually move down to the layer furthest from the first node.
Breadth search uses an abstract queue instead of an array to sort visited vertices.

Map.prototype.bfs = function (s) {
  let quenen = [];
    this.marked[s] = true;
    quenen.push(s);
    while(quenen.length > 0){
        let v = quenen.shift();
        if(v === undefined){
            console.log(v+'undefined');
        }       
        for(let i in this.adj[v]){
            if(!this.marked[i]){
               this.edgeTo[i] = v;
               this.marked[i] = true;
               quenen.push(i);
            }
        }
    }
}

principle

Find unreachable vertices adjacent to the current vertex and add them to the accessed vertex list and queue.
Take the next vertex from the graph and add it to the accessed list vertex.
Add all unreachable vertices adjacent to V to the queue.

Find shortest path

Breadth first search shortest path

// bfs function
function bfs(s) {
    var queue = [];
    this.marked[s] = true;
    queue.push(s); //Add to end of queue
    while (queue.length > 0) {
        var v = queue.shift(); //Remove from team leader
        if (v == undefined) {
            print("Visisted vertex:  " + v);
        }
        for each(var w in this.adj[v]) {
            if (!this.marked[w]) {
                this.edgeTo[w] = v;
                this.marked[w] = true;
                queue.push(w);
            }
        }
    }
}

Topological sorting

Topological sorting sorts all vertices of a directed graph so that the directed edge points from the front vertex to the back vertex.

Topological sorting algorithm

Keywords: Javascript Front-end data structure

Added by stevenm187 on Thu, 27 Jan 2022 02:35:01 +0200