JavaScript数据结构与算法7

110 阅读3分钟

参考

字典(dict) | 映射(Map)

  • { key:value },以键值对存储元素
    • key不可以重复,value可以重复,类似js中的Object
function Dictionary() {
  // 字典属性
  this.items = {};

  // set(key,value):往字典添加键值对
  Dictionary.prototype.set = function (key, value) {
    this.items[key + ""] = value;
    return true;
  };

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

  // remove(key):根据key从字典中移除键值对
  Dictionary.prototype.remove = function (key) {
    if (!this.has(key)) return false;
    delete this.items[key + ""];
    return true;
  };

  // get(key):根据key去获取value
  Dictionary.prototype.get = function (key) {
    if (!this.has(key)) return undefined;
    return this.items[key + ""];
  };

  // keys():以数组的形式返回所有的keys
  Dictionary.prototype.keys = function () {
    return Object.keys(this.items);
  };
}

// 测试代码
var dictionary = new Dictionary();
console.log(dictionary.set("name", "hao"));
console.log(dictionary.set("age", 18));
console.log(dictionary.keys());


console.log(dictionary.get("age"));
console.log(dictionary.remove("name"));
console.log(dictionary.get("name"));
console.log(dictionary.keys());

图(Graph)

  • 六度空间理论

    • 世界上任何两个互相不认识的人,只需要很少的中间人就可以建立联系
  • 适用于复杂的关系网

  • 由一组顶点(Vertex)、一组边(Edge)变构成

    • 相邻顶点:由一条边连接的两个顶点
    • 度:相邻顶点的数量
    • 路径:从一个顶点到另一个顶点所经过的顶点序列:V1、V2...
  • 邻接矩阵表示法

    • 行列数为顶点数,矩阵值代表顶点间的关系
      • A、B、C -> 0、1、2
[
  [0,1,1],
  [1,0,0],
  [1,0,0]
]
  • 邻接表表示法
    • 由每个顶点和此顶点的相邻顶点列表组成
  • 图的遍历:每个顶点访问一次,不能重复访问同一顶点
    • BFS(Breadth-First Search)
      • A、B、C、D、F、E、G、H、I
    • DFS(Depth-First Search)
      • A、B、E、I、F、C、D、G、H
  • Stack
function Stack(){
  this.items = [];

  // push(Element):将元素压入栈
  Stack.prototype.push = function(Element){
      this.items.push(Element);
  }
  // pop():取出栈顶元素
  Stack.prototype.pop = function(){
      return this.items.pop();
  }
  
  // peek():查看栈顶元素
  Stack.prototype.peek = function(){
      return this.items[this.items.length - 1];
  }            
  // isEmpty():判断栈是否空
  Stack.prototype.isEmpty = function(){
      return this.items.length === 0;
  }
  
  // size():获取栈中元素个数
  Stack.prototype.size = function(){
      return this.items.length;
  }            
  // toString():将栈结构用字符形式表示
  Stack.prototype.toString = function(){
      var resultString = '';
      for(var i = 0; i < this.items.length; i ++){
          resultString += this.items[i] + '';
      }    
      return resultString;
  }
}
  • Queue
function Queue(){
  this.items = [];

  // enqueue(element)
  Queue.prototype.enqueue = function(element){
      this.items.unshift(element);
  }
  // dequeue()
  Queue.prototype.dequeue = function(){
      return this.items.pop();
  }
  // front():返回队头元素
  Queue.prototype.front = function(){
      return this.items[this.items.length - 1];
  }
  // isEmpty()
  Queue.prototype.isEmpty = function(){
      return this.items.length === 0;
  }
  // size()
  Queue.prototype.size = function(){
      return this.items.length;
  }
  // toString()
  Queue.prototype.toString = function(){
      var result = '';
      for(var i = 0; i < this.items.length; i ++){
          result += this.items[i];
      }
      return result;
  }
}
  • Graph
/*
   边用字典结构,key存储顶点,[]存储邻接顶点
   {
     'A':[],
     'B':[],
     ...
   }
*/
function Graph() {
  this.vertexes = []; // 顶点
  this.edges = new Dictionary(); // 边


  // addVertex(v):添加顶点
  Graph.prototype.addVertex = function (v) {
    this.vertexes.push(v);
    this.edges.set(v, []);
  };
  // addEdge(v1,v2):添加边
  Graph.prototype.addEdge = function (v1, v2) {
    this.edges.get(v1).push(v2);
    this.edges.get(v2).push(v1);
  };

  // toString():用字符形式表示邻接表
  Graph.prototype.toString = function () {
    var Rstr = "";
    for (var i = 0; i < this.vertexes.length; i++) {
      Rstr += this.vertexes[i] + ":";
      Rstr += this.edges.get(this.vertexes[i]).join(" ");
      Rstr += "\n";
    }
    return Rstr;
  };

  // initializeColor():返回顶点颜色状态数组
  Graph.prototype.initializeColor = function () {
    var colors = [];
    for (var i = 0; i < this.vertexes.length; i++) {
      colors[this.vertexes[i]] = "white";
    }
    return colors;
  };

  // 初始化状态颜色:
  //    白色(未入队或栈、未访问此节点)
  //    灰色(已入队或栈,未访问)
  //    黑色(已入队或栈,已访问)
  // bfs():广度优先搜索
  Graph.prototype.bfs = function (v) {
    var bfsStr = "";
    // 1、获取顶点颜色状态数组
    var colors = this.initializeColor();
    // 2、创建队列,用于存储顶点
    var queue = new Queue();
    queue.enqueue(v);
    colors[v] = "gray";
    // 3、遍历非空队列
    while (!queue.isEmpty()) {
      // 3.1、取出队头元素
      var v_head = queue.dequeue();
      // 3.2、取出队头元素的邻接顶点,遍历邻接顶点,将是白色状态的数组入队,置为灰
      var nearEdges = this.edges.get(v_head);
      for (var i = 0; i < nearEdges.length; i++) {
        var tempEdges = nearEdges[i];
        if (colors[tempEdges] == "white") {
          queue.enqueue(tempEdges);
          colors[tempEdges] = "gray";
        }
      }
      bfsStr += v_head + "->";
      colors[v_head] = "black";
    }
    return bfsStr;
  };


  // dfs():深度优先搜索,非递归:用栈存储实现
  Graph.prototype.dfs = function (v) {
    var bfsStr = "";
    // 1、获取顶点颜色状态数组
    var colors = this.initializeColor();
    // 2、创建栈,用于存储顶点
    var stack = new Stack();
    stack.push(v);
    colors[v] = "gray";
    // 3、遍历非空栈
    while (!stack.isEmpty()) {
      // 3.1、取出栈顶元素
      var v_head = stack.pop();
      // 3.2、取出栈顶元素的邻接顶点,遍历邻接顶点,将是白色状态的数组入队,置为灰
      var nearEdges = this.edges.get(v_head);
      for (var i = 0; i < nearEdges.length; i++) {
        var tempEdges = nearEdges[i];
        if (colors[tempEdges] == "white") {
          stack.push(tempEdges);
          colors[tempEdges] = "gray";
        }
      }
      bfsStr += v_head + "->";
      colors[v_head] = "black";
    }
    return bfsStr;
  };


  // 递归实现dfs
  Graph.prototype.dfs = function (v, colors) {
    // 1、每次递归将顶点置为灰色
    colors[v] = "gray";
    console.log(v);
    // 2、遍历邻接顶点,将白色状态的邻接顶点进行递归调用
    var nearEdges = this.edges.get(v);
    for (var i = 0; i < nearEdges.length; i++) {
      var temp_edges = nearEdges[i];
      if (colors[temp_edges] == "white") {
        this.dfs(temp_edges, colors);
      }
    }
    colors[v] = "black";
  };
}

// 测试代码
  var graph = new Graph();
  var myVertexes = ["A", "B", "C", "D", "E", "F", "G", "H", "I"];
  for (var i = 0; i < myVertexes.length; i++) {
    graph.addVertex(myVertexes[i]);
  }
  
  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");
  
  console.log(graph.toString());
  console.log(graph.initializeColor());
  
  console.log(graph.bfs(graph.vertexes[0]));
  console.log(graph.dfs(graph.vertexes[0], graph.initializeColor()));

  • 队列实现bfs、栈实现的dfs
    • bfs把B作为了第一个邻接顶点
    • dfs把D作为了第一个邻接顶点
  • 递归实现的dfs
    • 把B作为了A的第一个邻接顶点

完整代码

function Dictionary(){
  // 字典属性
  this.items = {};

  // set(key,value):往字典添加键值对
  Dictionary.prototype.set = function(key,value){
    this.items[key + ''] = value;
    return true;
  }

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

  // remove(key):根据key从字典中移除键值对
  Dictionary.prototype.remove = function(key){
    if(!this.has(key))
      return false;
    delete this.items[key + ''];
    return true;
  }

  // get(key):根据key去获取value
  Dictionary.prototype.get = function(key){
    if(!this.has(key))
      return undefined;
    return this.items[key + ''];
  }

  // keys():以数组的形式返回所有的keys
  Dictionary.prototype.keys = function(){
    return Object.keys(this.items);
  }
}
function Queue(){
  this.items = [];

  // enqueue(element)
  Queue.prototype.enqueue = function(element){
      this.items.unshift(element);
  }
  // dequeue()
  Queue.prototype.dequeue = function(){
      return this.items.pop();
  }
  // front():返回队头元素
  Queue.prototype.front = function(){
      return this.items[this.items.length - 1];
  }
  // isEmpty()
  Queue.prototype.isEmpty = function(){
      return this.items.length === 0;
  }
  // size()
  Queue.prototype.size = function(){
      return this.items.length;
  }
  // toString()
  Queue.prototype.toString = function(){
      var result = '';
      for(var i = 0; i < this.items.length; i ++){
          result += this.items[i];
      }
      return result;
  }
}
function Stack(){
  this.items = [];

  // push(Element):将元素压入栈
  Stack.prototype.push = function(Element){
      this.items.push(Element);
  }
  // pop():取出栈顶元素
  Stack.prototype.pop = function(){
      return this.items.pop();
  }
  
  // peek():查看栈顶元素
  Stack.prototype.peek = function(){
      return this.items[this.items.length - 1];
  }            
  // isEmpty():判断栈是否空
  Stack.prototype.isEmpty = function(){
      return this.items.length === 0;
  }
  
  // size():获取栈中元素个数
  Stack.prototype.size = function(){
      return this.items.length;
  }            
  // toString():将栈结构用字符形式表示
  Stack.prototype.toString = function(){
      var resultString = '';
      for(var i = 0; i < this.items.length; i ++){
          resultString += this.items[i] + '';
      }    
      return resultString;
  }
}

// 通过邻接表实现图的表示
/*
边用字典结构,key存储顶点,[]存储邻接顶点
{
 'A':[],
 'B':[],
 ...
}
*/
function Graph(){
  this.vertexes = [];// 顶点
  this.edges = new Dictionary();// 边

  // addVertex(v):添加顶点
  Graph.prototype.addVertex = function(v){
    this.vertexes.push(v);
    this.edges.set(v,[]);
  }  
  // addEdge(v1,v2):添加边
  Graph.prototype.addEdge = function(v1,v2){
    this.edges.get(v1).push(v2);
    this.edges.get(v2).push(v1);
  }
  // toString():用字符形式表示邻接表
  Graph.prototype.toString = function(){
    var Rstr = '';
    for(var i = 0; i < this.vertexes.length; i ++){
      Rstr += this.vertexes[i] + ':';
      Rstr += this.edges.get(this.vertexes[i]).join(' ');
      Rstr += '\n';
    }
    return Rstr;
  }
  // initializeColor():返回顶点颜色状态数组
  Graph.prototype.initializeColor = function(){
    var colors = [];
    for(var i = 0; i < this.vertexes.length; i ++){
      colors[this.vertexes[i]] = 'white';
    }
    return colors;
  }
  // bfs():广度优先搜索
  Graph.prototype.bfs = function(v){
    var bfsStr = '';
    // 1、获取顶点颜色状态数组
    var colors = this.initializeColor();
    // 2、创建队列,用于存储顶点
    var queue = new Queue();
    queue.enqueue(v);
    colors[v] = 'gray';
    // 3、遍历非空队列
    while(!queue.isEmpty()){
      // 3.1、取出队头元素
      var v_head = queue.dequeue();
      // 3.2、取出队头元素的邻接顶点,遍历邻接顶点,将是白色状态的数组入队,置为灰
      var nearEdges = this.edges.get(v_head);
      for(var i = 0; i < nearEdges.length; i ++){
        var tempEdges = nearEdges[i];
        if(colors[tempEdges] == 'white'){
          queue.enqueue(tempEdges);
          colors[tempEdges] = 'gray';
        }
      }  
      bfsStr += v_head + '->'
      colors[v_head] = 'black';
    }
    return bfsStr;
  }
  
  // dfs():深度优先搜索,非递归:用栈存储实现
  /*
  Graph.prototype.dfs = function(v){
    var bfsStr = '';
    // 1、获取顶点颜色状态数组
    var colors = this.initializeColor();
    // 2、创建栈,用于存储顶点
    var stack = new Stack();
    stack.push(v);
    colors[v] = 'gray';
    // 3、遍历非空栈
    while(!stack.isEmpty()){
      // 3.1、取出栈顶元素
      var v_head = stack.pop();
      // 3.2、取出栈顶元素的邻接顶点,遍历邻接顶点,将是白色状态的数组入队,置为灰
      var nearEdges = this.edges.get(v_head);
      for(var i = 0; i < nearEdges.length; i ++){
        var tempEdges = nearEdges[i];
        if(colors[tempEdges] == 'white'){
          stack.push(tempEdges);
          colors[tempEdges] = 'gray';
        }
      }  
      bfsStr += v_head + '->'
      colors[v_head] = 'black';
    }
    return bfsStr
  }
  */

  // 递归实现dfs
  Graph.prototype.dfs = function(v,colors){
    // 1、每次递归将顶点置为灰色
    colors[v] = 'gray';
    console.log(v);
    // 2、遍历邻接顶点,将白色状态的邻接顶点进行递归调用
    var nearEdges = this.edges.get(v);
    for(var i = 0; i < nearEdges.length; i ++){
      var temp_edges = nearEdges[i];
      if(colors[temp_edges] == 'white'){
        this.dfs(temp_edges,colors);
      }
    }
    colors[v] = 'black';
  }

}
// 测试代码
var graph = new Graph();
var myVertexes = ["A", "B", "C", "D", "E", "F", "G", "H", "I"];
for (var i = 0; i < myVertexes.length; i++) {
  graph.addVertex(myVertexes[i]);
}

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");

console.log(graph.toString());
console.log(graph.initializeColor());

console.log(graph.bfs(graph.vertexes[0]));
console.log(graph.dfs(graph.vertexes[0], graph.initializeColor()));