数据结构 - 图

本文深入探讨了图数据结构的实现与邻接表表示,详细解析了广度优先搜索(BFS)与深度优先搜索(DFS)两种图遍历算法的原理及实现过程,包括算法流程、代码示例及应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据结构 - 图,使用邻接表。
图遍历方式:

  1. 广度优先 - 优先遍历横向 - 队列
  2. 深度优先 - 优先遍历纵向 - 栈
// 栈实现
// ES5
var Stack = function() {
  var items = [];  // 私有

  // 栈顶添加元素
  this.push = function(element) {
    items.push(element);
  };

  // 栈顶拿出元素
  this.pop = function() {
    return items.pop();
  };

  // 检查栈顶元素
  this.peek = function() {
    return items[items.length - 1];
  };

  // 检查栈是否为空
  this.isEmpty = function() {
    return items.length == 0;
  };

  // 清除栈
  this.clear = function() {
    items = [];
  };

  // 获取栈长度
  this.size = function() {
    return items.length;
  };

  // 检查items
  this.getItem = function() {
    return items;
  };
};

// 队列实现
// ES5
var Queue = function() {
  var items = [];

  // 队列入列
  this.enqueue = function(element) {
    items.push(element);
  };

  // 队列出列
  this.dequeue = function() {
    return items.shift();
  };

  // 检查队列第一个元素
  this.front = function() {
    return items[0];
  };

  // 检查队列是否为空
  this.isEmpty = function() {
    return items.length == 0;
  };

  // 获取队列长度
  this.size = function() {
    return items.length;
  };

  // 检查items
  this.getItem = function() {
    return items;
  };
};

// 图实现 - 邻接表
// ES5
var Graph = function() {

  // 顶点
  var vertices = [];
  // 边
  var adjList = {};

  // 1.添加顶点
  this.addVertex = function(v) {
    vertices.push(v);
    adjList[v] = [];
  };

  // 2.添加边
  this.addEdge = function(a, b) {
    adjList[a].push(b);
    adjList[b].push(a);
  };

  // 3.打印邻接表
  this.print = function() {
    var s = '';
    for (var i in vertices) {
      var dingdian = vertices[i];
      s += dingdian + ' => ';
      var bian = adjList[dingdian];
      for (var j in bian) {
        s += bian[j];
      }
      s += '\n';
    }
    console.log(s);
  };

  /**
   * 图遍历方式:
   * 1-广度优先 - 优先遍历横向 - 队列
   * 2-深度优先 - 优先遍历纵向 - 栈
   *
   * 图遍历思路:
   * 节点状态:3中
   * 1. 未发现(尚未发现此节点)
   * 2. 已经发现(发现其他节点连接到此,但未查找此节点连接的全部节点)
   * 3. 已经探索(已经发现此节点连接的全部节点)
   *
   * */

    // 广度优先遍历
    // 初始化颜色 white-未发现 grey-已经发现 black-已经探索
    var initColor = function() {
      var color = {};
      for (var i in vertices) {
        color[vertices[i]] = 'white';
      }
      return color;
    };
    this.bfs = function(v, callback) {
      // 获取初始化顶点color
      var color = initColor();
      // 初始化队列
      var queue = new Queue();
      queue.enqueue(v);

      // 检查队列是否为空
      while(!queue.isEmpty()) {
        // 出列
        var now = queue.dequeue();
        // 获取所有边,遍历
        var bian = adjList[now];
        for (var i in bian) {
          var w = bian[i];
          if (color[w] == 'white') {
            // 未发现顶点全部入列,并且标记未已发现
            color[w] = 'grey';
            queue.enqueue(w);
          }
        }
        // 出列顶点标记为已探索
        color[now] = 'black';
        // 用于输出
        if (callback) {
          callback(now);
        }
      }
    };

  /**
   * 广度优先算法
   * distance - 记录d
   * pred - 记录回溯路径
   *
   * */
  this.BFS = function(v, callback) {
    // 获取初始化顶点color
    var color = initColor();
    // 初始化队列
    var queue = new Queue();
    queue.enqueue(v);

    // 初始化
    var d = {};
    var pred = {};
    for (var i in vertices) {
      d[vertices[i]] = 0;
      pred[vertices[i]] = null;
    }

    // 检查队列是否为空
    while(!queue.isEmpty()) {
      // 出列
      var now = queue.dequeue();
      // 获取所有边,遍历
      var bian = adjList[now];
      for (var i in bian) {
        var w = bian[i];
        if (color[w] == 'white') {
          // 未发现顶点全部入列,并且标记未已发现
          color[w] = 'grey';

          // 设置回溯点
          pred[w] = now;
          d[w] = d[now] + 1;

          queue.enqueue(w);
        }
      }
      // 出列顶点标记为已探索
      color[now] = 'black';
      // 用于输出
      if (callback) {
        callback(now);
      }
    }
    return {
      pred: pred,
      d: d
    };
  };

  // 深度优先算法 - 递归
  var dfsVisite = function(u, color, callback) {
    color[u] = 'grey';
    var n = adjList[u];
    for (var i in n) {
      var w = n[i];
      if (color[w] == 'white') {
        dfsVisite(w, color, callback);
      }
    }
    color[u] = 'black';
    if (callback) {
      callback(u);
    }
  };
  this.dfs = function(v, callback) {
    var color = initColor();
    dfsVisite(v, color, callback);
  };
};


var g = new Graph();
g.addVertex('A');
g.addVertex('B');
g.addVertex('C');
g.addVertex('D');
g.addVertex('E');
g.addVertex('F');

g.addEdge('A', 'B');
g.addEdge('A', 'C');
g.addEdge('A', 'D');
g.addEdge('B', 'E');
g.addEdge('B', 'F');
g.addEdge('C', 'D');


// 添加新路径
g.addEdge('D', 'F');

// 最短路径
var shortest = function(from, to) {
  var s = g.BFS(from);
  console.log(s);
  var v = to; // 设置当前点
  var path = new Stack();

  while(v != from) {
    path.push(v);
    v = s.pred[v];  // 回溯点
  }
  path.push(v);

  var str = '';
  while (!path.isEmpty()) {
    str += path.pop() + ' => ';
  }

  str = str.slice(0, str.length-4);
  console.log(str);
};
shortest('A', 'F');
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值