JavaScript implementation structure diagram

JavaScript implementation structure diagram

First, graph theory

Introduction 1.1. Map

What is a view?

  • FIG structure is a the tree structure somewhat similar to a data structure;
  • Graph theory is a branch of mathematics, and, in mathematics, a tree graph;
  • The picture shows the graph theory to the study, research vertices and edges composed of graphical mathematical theory and methods;
  • The main purpose of the study is: connections between things , the apex representative of things , side representatives between two things relations ;

Figure features:

  • A set of vertices : usually V (Vertex) denotes the set of vertices;
  • A set of edges : usually E represents the set of edges (Edge);
    • Edges drawn between the vertex and the vertex;
    • Side can be directed also be undirected. A ---- B represents example undirected, A ---> B represents directed;

FIG commonly used terms:

  • Vertices: represents a graph of nodes ;

  • Edge: represents the vertex and vertices between a connection ;

  • Adjacent vertices: are connected by an edge with vertex referred to adjacent vertices ;

  • Of: a vertex of a number of adjacent vertices ;

  • path:

    • Simple path: a simple route request does not contain duplicate vertices;
    • Loop: The first and last vertex of a vertex same path along the loop;
  • Undirected graph: FIG all edges are without direction;

  • Directed graph: all edges in the graph are there directions;

  • Figure no right: no right edges in the graph does not sense any heavy weights;

  • FIG weighted: to have certain meanings weights of weighted graph;

Represents 1.2. FIG.

Adjacency matrix

FIG commonly expressed as: adjacency matrix .

  • Two-dimensional array can be used to represent the adjacency matrix;

  • Let adjacency matrix for each node and an associated integer , the integer value as a subscript of an array ;

  • Using a two-dimensional array to represent the vertices between the connection ;

image-20200303213913574

As shown in FIG:

  • Two-dimensional array of 0 indicates no connection, 1 indicates there is connection;
  • Such as: A [0] [3] = 1, represents the connection between A, and C;
  • Diagonal adjacency matrix values ​​are zero, showing A - A, B - B, and the like from the circuit are not connected (no connection between him and themselves);
  • If, the adjacency matrix is ​​a non-directed graph should be symmetric on the diagonal matrix elements are all 0;

Adjacency matrix of the problem:

  • If a graph is sparse graphs , the adjacency matrix in the presence of a large number of 0 , resulting in waste of storage space;
Adjacency list

FIG Another common way to represent: adjacency table .

  • FIG adjacent table in each of the vertex and the adjacent vertices and a list of vertices composition;
  • This list is stored in a number of ways, such as: an array / list / dictionary (hash table) and so can;

image-20200303215312091

As shown in FIG:

  • Can be clearly seen in FIG. A adjacent the B, C, D , A and if we want to represent the vertices adjacent to the vertex (edge), they are stored by a value corresponding to the (value) of the A array / chain / dictionary in.
  • Then, A can be very easily removed by a key corresponding data (Key);

Adjacency list of questions:

  • Adjacency table can be simply drawn out degree , i.e. a number of vertex points to another vertex;
  • However, calculating the adjacent table -degree (the number of another vertex point to a vertex is called the degree of the vertex) difficult. In this case need to construct an inverse adjacency table to calculate the effective degree;

Second, the package structure of FIG.

In the implementation process using the adjacency list of edges that represent manner, using the dictionary class to store the adjacent table.

2.1. Adding the dictionary class and class queues

First need to introduce, to be followed dictionaries classes and class queues used prior to implementation:

    //封装字典类
function Dictionary(){
  //字典属性
  this.items = {}

  //字典操作方法
  //一.在字典中添加键值对
  Dictionary.prototype.set = function(key, value){
    this.items[key] = value
  }

  //二.判断字典中是否有某个key
  Dictionary.prototype.has = function(key){
    return this.items.hasOwnProperty(key)
  }

  //三.从字典中移除元素
  Dictionary.prototype.remove = function(key){
    //1.判断字典中是否有这个key
    if(!this.has(key)) return false

    //2.从字典中删除key
    delete this.items[key]
    return true
  }

  //四.根据key获取value
  Dictionary.prototype.get = function(key){
    return this.has(key) ? this.items[key] : undefined
  }

  //五.获取所有keys
  Dictionary.prototype.keys = function(){
    return Object.keys(this.items)
  }

  //六.size方法
  Dictionary.prototype.keys = function(){
    return this.keys().length
  }

  //七.clear方法
  Dictionary.prototype.clear = function(){
    this.items = {}
  }
}

   // 基于数组封装队列类
    function Queue() {
    // 属性
      this.items = []
    // 方法
    // 1.将元素加入到队列中
    Queue.prototype.enqueue = element => {
      this.items.push(element)
    }

    // 2.从队列中删除前端元素
    Queue.prototype.dequeue = () => {
      return this.items.shift()
    }

    // 3.查看前端的元素
    Queue.prototype.front = () => {
      return this.items[0]
    }

    // 4.查看队列是否为空
    Queue.prototype.isEmpty = () => {
      return this.items.length == 0;
    }

    // 5.查看队列中元素的个数
    Queue.prototype.size = () => {
      return this.items.length
    }

    // 6.toString方法
    Queue.prototype.toString = () => {
      let resultString = ''
        for (let i of this.items){
          resultString += i + ' '
        }
        return resultString
      }
    }

2.2. Creating graphs

Create graphs Graph, and add basic properties, commonly used method of re-drawing class implementation:

    //封装图类
    function Graph (){
      //属性:顶点(数组)/边(字典)
      this.vertexes = []  //顶点
      this.edges = new Dictionary() //边
      }

2.3 Add the vertex and edge

as the picture shows:

image-20200303235132868

Create a vertex array object vertexes memory map; creating a dictionary object side edges of the memory map, wherein the vertex key, value storage key vertex array of adjacent vertices.

Code:

      //添加方法
      //一.添加顶点
      Graph.prototype.addVertex = function(v){
        this.vertexes.push(v)
        this.edges.set(v, []) //将边添加到字典中,新增的顶点作为键,对应的值为一个存储边的空数组
      }
      //二.添加边
      Graph.prototype.addEdge = function(v1, v2){//传入两个顶点为它们添加边
        this.edges.get(v1).push(v2)//取出字典对象edges中存储边的数组,并添加关联顶点
        this.edges.get(v2).push(v1)//表示的是无向表,故要添加互相指向的两条边
      }

2.4. Convert a string from the

FIG adding Graph class toString method, implemented in the form of the adjacency list of each vertex Output FIG.

Code:

      //三.实现toString方法:转换为邻接表形式
      Graph.prototype.toString = function (){
        //1.定义字符串,保存最终结果
        let resultString = ""

        //2.遍历所有的顶点以及顶点对应的边
        for (let i = 0; i < this.vertexes.length; i++) {//遍历所有顶点
          resultString += this.vertexes[i] + '-->'
          let vEdges = this.edges.get(this.vertexes[i])
          for (let j = 0; j < vEdges.length; j++) {//遍历字典中每个顶点对应的数组
            resultString += vEdges[j] + '  ';
          }
          resultString += '\n'
        }
        return resultString
      }

Test code:

   //测试代码
    //1.创建图结构
    let graph = new Graph()

    //2.添加顶点
    let myVertexes = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
    for (let i = 0; i < myVertexes.length; i++) {
      graph.addVertex(myVertexes[i])
    }

    //3.添加边
    graph.addEdge('A', 'B')
    graph.addEdge('A', 'C')
    graph.addEdge('A', 'D')
    graph.addEdge('C', 'D')
    graph.addEdge('C', 'G')
    graph.addEdge('D', 'G')
    graph.addEdge('D', 'H')
    graph.addEdge('B', 'E')
    graph.addEdge('B', 'F')
    graph.addEdge('E', 'I')

    //4.输出结果
    console.log(graph.toString());

Test Results:

image-20200303233737451

2.5. Graph traversal

Graph traversal thought:

  • Like traverse traverse the ideas and thoughts of the tree diagram, which means you need to figure all vertices are visited again, and can not have duplicate access (toString method above will repeat visits);

Graph traversal two algorithms:

  • BFS (Breadth - First Search, abbreviated BFS );
  • Depth-first search (Depth - First Search, referred to as the DFS );
  • Two kinds of traversal algorithms need to specify the first vertex to be visited ;

In order to record whether the vertex has been visited, using three colors to indicate their status

  • White : indicates that the vertex has not been accessed;
  • Gray : indicates that the vertex is visited, but it is not completely adjacent vertices visited;
  • Black : indicates that the vertex is visited, and all of its neighboring vertices have been visited;

First of all vertices encapsulation method initializeColor initialization white figure, the code to achieve the following:

      //四.初始化状态颜色
      Graph.prototype.initializeColor = function(){
        let colors = []
        for (let i = 0; i < this.vertexes.length; i++) {
           colors[this.vertexes[i]] = 'white';
        }
        return colors
      }
BFS

Breadth-first search algorithm ideas:

  • Breadth-first search algorithm will begin to traverse the map from the first vertex specified to access all of its neighboring vertices, like a visit to one figure;
  • It can be said depth after the first width of each vertex traversing the drawing;

image-20200303233840691

Realization of ideas:

Based queue can simply realize the breadth-first search algorithm:

  • First create a queue Q (into the tail, the header);
  • The packaging method call initializeColor all vertices is initialized to white;
  • Specifies the first vertex A, labeled A to gray (visited node), and placed in the queue Q, A;
  • Cycle through the elements in the queue, the queue as long as Q is not empty, it performs the following operations:
    • A first gray Q is taken out from the header;
    • After removing the A, all not been accessed (white) were added sequentially adjacent vertices A, Q queue from the queue tail, and becomes gray. In order to ensure, gray queued adjacent vertices will not be repeated;
    • After the addition of all the neighboring nodes A, Q, A to black, in the next cycle is removed outside Q;

Code:

      //五.实现广度搜索(BFS)
      //传入指定的第一个顶点和处理结果的函数
      Graph.prototype.bfs = function(initV, handler){
        //1.初始化颜色
        let colors = this.initializeColor()

        //2.创建队列
        let que = new Queue()

        //3.将顶点加入到队列中
        que.enqueue(initV)

        //4.循环从队列中取出元素,队列为空才停止
        while(!que.isEmpty()){
          //4.1.从队列首部取出一个顶点
          let v = que.dequeue()

          //4.2.从字典对象edges中获取和该顶点相邻的其他顶点组成的数组
          let vNeighbours = this.edges.get(v)

          //4.3.将v的颜色变为灰色
          colors[v] = 'gray'

          //4.4.遍历v所有相邻的顶点vNeighbours,并且加入队列中
          for (let i = 0; i < vNeighbours.length; i++) {
            const a = vNeighbours[i];
            //判断相邻顶点是否被探测过,被探测过则不加入队列中;并且加入队列后变为灰色,表示被探测过
            if (colors[a] == 'white') {
              colors[a] = 'gray'
              que.enqueue(a)
            }
          }

          //4.5.处理顶点v
          handler(v)

          //4.6.顶点v所有白色的相邻顶点都加入队列后,将顶点v设置为黑色。此时黑色顶点v位于队列最前面,进入下一次while循环时会被取出
          colors[v] = 'black'
        }
      }

Detailed process:

When the traversal is specified for the first vertex A:

  • As a shown in FIG., The edges extracted in the dictionary with the adjacent A and has not been visited white vertex B, C, D que into the queue and becomes gray to black and then dequeued A ;
  • Next, as shown in b, the edges are extracted in the dictionary adjacent to B and has not been visited white vertices E, F que into the queue and becomes gray to black and then dequeued B ;

image-20200306144336380

  • As shown in FIG. C, the dictionary will be removed adjacent the edges of the C and has not been visited white vertex G (A, D has turned gray, but also adjacent, it is not enqueued) in the queue in the que and becomes gray to black and then dequeued C;
  • Next, as shown in FIG. D, taken out in the dictionary edges adjacent to D and has not been accessed in a queue que apex H white and become gray, to black and then D removed from the queue.

image-20200306144427242

This cycle until the queue element is 0, i.e. all vertices blackened queue and removed after stop when all the vertices in the graph has been traversed.

Test code:

    //测试代码
    //1.创建图结构
    let graph = new Graph()

    //2.添加顶点
    let myVertexes = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
    for (let i = 0; i < myVertexes.length; i++) {
      graph.addVertex(myVertexes[i])
    }

    //3.添加边
    graph.addEdge('A', 'B')
    graph.addEdge('A', 'C')
    graph.addEdge('A', 'D')
    graph.addEdge('C', 'D')
    graph.addEdge('C', 'G')
    graph.addEdge('D', 'G')
    graph.addEdge('D', 'H')
    graph.addEdge('B', 'E')
    graph.addEdge('B', 'F')
    graph.addEdge('E', 'I')
    
    //4.测试bfs遍历方法
    let result = ""
    graph.bfs(graph.vertexes[0], function(v){
      result += v + "-"
    })
    console.log(result);

Test Results:

image-20200304120023711

Visible, breadth-first search order is installed will not be repeated traversing of all vertices.

Depth-first search

Breadth-first algorithm ideas:

  • The depth-first search algorithm will start from a first traversing FIG specified vertex traversal until the last vertex of the path have been visited so far along a path;
  • And then fallback to explore the path, i.e., along the original path to the wide and deep to traverse each vertex in the graph;

image-20200304120355088

Realization of ideas:

  • You can use the stack structure to achieve the depth-first search algorithm;
  • Depth-first traversal order of the search algorithm of the binary search tree in preorder traversal is similar, it can also be used recursively to achieve (the recursive nature is a function of stack calls).

Dfs defines a method for recursive call dfsVisit, a method is defined for each vertex dfsVisit descend figures: recursive depth-first search algorithm.

In dfs method:

  • First, call the method initializeColor all vertices is initialized to white;
  • Then, call the vertices of the graph traversal methods dfsVisit;

In dfsVisit method:

  • First, the incoming specified node v labeled gray ;
  • Next, the process vertex V;
  • Then, access to the adjacent vertices V;
  • Finally, the vertex v labeled black;

Code:

      //六.实现深度搜索(DFS)
      Graph.prototype.dfs = function(initV, handler){
        //1.初始化顶点颜色
        let colors = this.initializeColor()

        //2.从某个顶点开始依次递归访问
        this.dfsVisit(initV, colors, handler)
      }

      //为了方便递归调用,封装访问顶点的函数,传入三个参数分别表示:指定的第一个顶点、颜色、处理函数
      Graph.prototype.dfsVisit = function(v, colors, handler){
        //1.将颜色设置为灰色
        colors[v] = 'gray'

        //2.处理v顶点
        handler(v)

        //3.访问V的相邻顶点
        let vNeighbours = this.edges.get(v)
        for (let i = 0; i < vNeighbours.length; i++) {
          let a = vNeighbours[i];
          //判断相邻顶点是否为白色,若为白色,递归调用函数继续访问
          if (colors[a] == 'white') {
            this.dfsVisit(a, colors, handler)
          }
          
        }

        //4.将v设置为黑色
        colors[v] = 'black'
      }

Detailed process:

Here to explain why the code Step 3: Go to the specified adjacent vertices vertices.

  • A vertex to specify, for example, start by adjacent memory array composed of vertexes A and the corresponding vertices of the dictionary object edges adjacent vertices removed:

image-20200304155916036

  • Step : A vertex becomes gray, then enters the first for loop, traversing the white adjacent vertices A: B, C, D; in the first cycle for cycle (execution B), B satisfies the vertex : colors == "white", a recursive trigger, re-invoke the method;
  • Step : B turns gray vertex, then enters the second for loop, traversing the white adjacent vertices B: E, F; (execution E), E vertices meet for the first cycle of the cycle: colors == "white", a recursive trigger, re-invoke the method;
  • Step : E becomes gray vertex, then into the third loop for traversing adjacent vertices E white: I; (perform I), I meet at the apex of the first cycle for cycle: colors == "white", a recursive trigger, re-invoke the method;
  • Step four : I vertex grayed out, then entered the fourth for loop, because the adjacent vertices E does not satisfy the apex I: colors == "white", stop the recursive call. Process is shown below:

image-20200304160536187

  • Step five : After the recursion all the way back up, back to the first third for loop continue with the second and third cycles ... which, during each execution cycle of the same reason as above, until the end of the recursion again after, and then return to the second for loop continues where the second and third cycles .... and so on ... until all vertices in the graph of complete access so far.

The figure below shows a complete traversal of the drawing process of each vertex:

  • Found indicates the visited vertex state becomes gray ;
  • Exploration represents both visited the vertex, also visited the apex of all adjacent vertices, the state becomes black ;
  • Since the vertex becomes gray after call handler handler, the output handler method for finding the sequence order of the vertices, namely: A, B, E, I, F, C, D, G, H.

image-20200304154745646

Test code:

    //测试代码
    //1.创建图结构
    let graph = new Graph()

    //2.添加顶点
    let myVertexes = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
    for (let i = 0; i < myVertexes.length; i++) {
      graph.addVertex(myVertexes[i])
    }

    //3.添加边
    graph.addEdge('A', 'B')
    graph.addEdge('A', 'C')
    graph.addEdge('A', 'D')
    graph.addEdge('C', 'D')
    graph.addEdge('C', 'G')
    graph.addEdge('D', 'G')
    graph.addEdge('D', 'H')
    graph.addEdge('B', 'E')
    graph.addEdge('B', 'F')
    graph.addEdge('E', 'I')
    
    //4.测试dfs遍历顶点
    let result = ""
    graph.dfs(graph.vertexes[0], function(v){
      result += v + "-"
    })
    console.log(result);
    

Test Results:

image-20200304125313739

2.6 The full realization

    //封装图结构
    function Graph (){
      //属性:顶点(数组)/边(字典)
      this.vertexes = []  //顶点
      this.edges = new Dictionary() //边

      //方法
      //添加方法
      //一.添加顶点
      Graph.prototype.addVertex = function(v){
        this.vertexes.push(v)
        this.edges.set(v, []) //将边添加到字典中,新增的顶点作为键,对应的值为一个存储边的空数组
      }
      //二.添加边
      Graph.prototype.addEdge = function(v1, v2){//传入两个顶点为它们添加边
        this.edges.get(v1).push(v2)//取出字典对象edges中存储边的数组,并添加关联顶点
        this.edges.get(v2).push(v1)//表示的是无向表,故要添加互相指向的两条边
      }

      //三.实现toString方法:转换为邻接表形式
      Graph.prototype.toString = function (){
        //1.定义字符串,保存最终结果
        let resultString = ""

        //2.遍历所有的顶点以及顶点对应的边
        for (let i = 0; i < this.vertexes.length; i++) {//遍历所有顶点
          resultString += this.vertexes[i] + '-->'
          let vEdges = this.edges.get(this.vertexes[i])
          for (let j = 0; j < vEdges.length; j++) {//遍历字典中每个顶点对应的数组
            resultString += vEdges[j] + '  ';
          }
          resultString += '\n'
        }
        return resultString
      }

      //四.初始化状态颜色
      Graph.prototype.initializeColor = function(){
        let colors = []
        for (let i = 0; i < this.vertexes.length; i++) {
           colors[this.vertexes[i]] = 'white';
        }
        return colors
      }

      //五.实现广度搜索(BFS)
      //传入指定的第一个顶点和处理结果的函数
      Graph.prototype.bfs = function(initV, handler){
        //1.初始化颜色
        let colors = this.initializeColor()

        //2.创建队列
        let que = new Queue()

        //3.将顶点加入到队列中
        que.enqueue(initV)

        //4.循环从队列中取出元素
        while(!que.isEmpty()){
          //4.1.从队列中取出一个顶点
          let v = que.dequeue()

          //4.2.获取和顶点相相邻的其他顶点
          let vNeighbours = this.edges.get(v)

          //4.3.将v的颜色变为灰色
          colors[v] = 'gray'

          //4.4.遍历v所有相邻的顶点vNeighbours,并且加入队列中
          for (let i = 0; i < vNeighbours.length; i++) {
            const a = vNeighbours[i];
            //判断相邻顶点是否被探测过,被探测过则不加入队列中;并且加入队列后变为灰色,表示被探测过
            if (colors[a] == 'white') {
              colors[a] = 'gray'
              que.enqueue(a)
            }
          }

          //4.5.处理顶点v
          handler(v)

          //4.6.顶点v所有白色的相邻顶点都加入队列后,将顶点v设置为黑色。此时黑色顶点v位于队列最前面,进入下一次while循环时会被取出
          colors[v] = 'black'
        }
      }

      //六.实现深度搜索(DFS)
      Graph.prototype.dfs = function(initV, handler){
        //1.初始化顶点颜色
        let colors = this.initializeColor()

        //2.从某个顶点开始依次递归访问
        this.dfsVisit(initV, colors, handler)
      }

      //为了方便递归调用,封装访问顶点的函数,传入三个参数分别表示:指定的第一个顶点、颜色、处理函数
      Graph.prototype.dfsVisit = function(v, colors, handler){
        //1.将颜色设置为灰色
        colors[v] = 'gray'

        //2.处理v顶点
        handler(v)

        //3.访问v相连的其他顶点
        let vNeighbours = this.edges.get(v)
        for (let i = 0; i < vNeighbours.length; i++) {
          let a = vNeighbours[i];
          //判断相邻顶点是否为白色,若为白色,递归调用函数继续访问
          if (colors[a] == 'white') {
            this.dfsVisit(a, colors, handler)
          }
          
        }

        //4.将v设置为黑色
        colors[v] = 'black'
      }
    }

Guess you like

Origin www.cnblogs.com/AhuntSun-blog/p/12636692.html