React Router
Graphtheory

图论基础知识

了解图论的基本概念、术语和基础理论

图论基础知识

图论是数学的一个分支,研究由顶点和边组成的图结构。它在计算机科学、网络分析、社交网络等领域有广泛应用。

什么是图?

图(Graph)是由一组顶点(Vertex)和一组边(Edge)组成的数学结构,用于表示对象之间的关系。

图 = 顶点集合 + 边集合
G = (V, E)

基本概念

  • 顶点(Vertex/Node):图中的基本元素,表示对象
  • 边(Edge):连接两个顶点的线,表示关系
  • 度(Degree):与顶点相连的边的数量
  • 路径(Path):从一个顶点到另一个顶点的边序列
  • 连通性(Connectivity):图中顶点之间的可达性

图的分类

1. 按边的方向分类

无向图(Undirected Graph)

边没有方向,表示双向关系。

// 无向图示例
const undirectedGraph = {
  vertices: ['A', 'B', 'C', 'D'],
  edges: [
    ['A', 'B'], // A 和 B 相连
    ['B', 'C'], // B 和 C 相连
    ['C', 'D'], // C 和 D 相连
    ['A', 'D']  // A 和 D 相连
  ]
};

有向图(Directed Graph)

边有方向,表示单向关系。

// 有向图示例
const directedGraph = {
  vertices: ['A', 'B', 'C', 'D'],
  edges: [
    ['A', 'B'], // A 指向 B
    ['B', 'C'], // B 指向 C
    ['C', 'D'], // C 指向 D
    ['D', 'A']  // D 指向 A
  ]
};

2. 按边的权重分类

无权图(Unweighted Graph)

边没有权重,只表示连接关系。

// 无权图
const unweightedGraph = {
  vertices: ['A', 'B', 'C'],
  edges: [
    ['A', 'B'],
    ['B', 'C'],
    ['A', 'C']
  ]
};

加权图(Weighted Graph)

边有权重,表示距离、成本等数值。

// 加权图
const weightedGraph = {
  vertices: ['A', 'B', 'C'],
  edges: [
    { from: 'A', to: 'B', weight: 5 },
    { from: 'B', to: 'C', weight: 3 },
    { from: 'A', to: 'C', weight: 8 }
  ]
};

3. 特殊图类型

完全图(Complete Graph)

任意两个顶点之间都有边相连。

// 完全图 K4
const completeGraph = {
  vertices: ['A', 'B', 'C', 'D'],
  edges: [
    ['A', 'B'], ['A', 'C'], ['A', 'D'],
    ['B', 'C'], ['B', 'D'],
    ['C', 'D']
  ]
};

二分图(Bipartite Graph)

顶点可以分为两个独立集合,所有边都连接不同集合的顶点。

// 二分图示例
const bipartiteGraph = {
  leftVertices: ['A', 'B', 'C'],
  rightVertices: ['X', 'Y', 'Z'],
  edges: [
    ['A', 'X'], ['A', 'Y'],
    ['B', 'Y'], ['B', 'Z'],
    ['C', 'X'], ['C', 'Z']
  ]
};

图的表示方法

1. 邻接矩阵(Adjacency Matrix)

使用二维数组表示图的连接关系。

// 邻接矩阵表示
class AdjacencyMatrix {
  constructor(vertices) {
    this.vertices = vertices;
    this.matrix = Array(vertices.length).fill().map(() => 
      Array(vertices.length).fill(0)
    );
  }
  
  // 添加边
  addEdge(from, to, weight = 1) {
    const fromIndex = this.vertices.indexOf(from);
    const toIndex = this.vertices.indexOf(to);
    
    if (fromIndex !== -1 && toIndex !== -1) {
      this.matrix[fromIndex][toIndex] = weight;
      this.matrix[toIndex][fromIndex] = weight; // 无向图
    }
  }
  
  // 检查是否有边
  hasEdge(from, to) {
    const fromIndex = this.vertices.indexOf(from);
    const toIndex = this.vertices.indexOf(to);
    return this.matrix[fromIndex][toIndex] > 0;
  }
  
  // 获取顶点的邻居
  getNeighbors(vertex) {
    const index = this.vertices.indexOf(vertex);
    const neighbors = [];
    
    for (let i = 0; i < this.vertices.length; i++) {
      if (this.matrix[index][i] > 0) {
        neighbors.push(this.vertices[i]);
      }
    }
    
    return neighbors;
  }
  
  // 打印矩阵
  print() {
    console.log('  ' + this.vertices.join(' '));
    for (let i = 0; i < this.matrix.length; i++) {
      console.log(this.vertices[i] + ' ' + this.matrix[i].join(' '));
    }
  }
}

// 使用示例
const graph = new AdjacencyMatrix(['A', 'B', 'C', 'D']);
graph.addEdge('A', 'B');
graph.addEdge('B', 'C');
graph.addEdge('C', 'D');
graph.addEdge('A', 'D');

console.log('邻接矩阵:');
graph.print();
console.log('A的邻居:', graph.getNeighbors('A'));

2. 邻接表(Adjacency List)

使用数组或哈希表存储每个顶点的邻居。

// 邻接表表示
class AdjacencyList {
  constructor() {
    this.vertices = new Map();
  }
  
  // 添加顶点
  addVertex(vertex) {
    if (!this.vertices.has(vertex)) {
      this.vertices.set(vertex, []);
    }
  }
  
  // 添加边
  addEdge(from, to, weight = 1) {
    this.addVertex(from);
    this.addVertex(to);
    
    this.vertices.get(from).push({ to, weight });
    this.vertices.get(to).push({ to: from, weight }); // 无向图
  }
  
  // 获取顶点的邻居
  getNeighbors(vertex) {
    return this.vertices.get(vertex) || [];
  }
  
  // 获取所有顶点
  getVertices() {
    return Array.from(this.vertices.keys());
  }
  
  // 打印图
  print() {
    for (const [vertex, neighbors] of this.vertices) {
      console.log(`${vertex} -> ${neighbors.map(n => n.to).join(', ')}`);
    }
  }
}

// 使用示例
const graph = new AdjacencyList();
graph.addEdge('A', 'B', 5);
graph.addEdge('B', 'C', 3);
graph.addEdge('C', 'D', 2);
graph.addEdge('A', 'D', 8);

console.log('邻接表:');
graph.print();
console.log('A的邻居:', graph.getNeighbors('A'));

3. 边列表(Edge List)

直接存储所有边的列表。

// 边列表表示
class EdgeList {
  constructor() {
    this.edges = [];
    this.vertices = new Set();
  }
  
  // 添加边
  addEdge(from, to, weight = 1) {
    this.edges.push({ from, to, weight });
    this.vertices.add(from);
    this.vertices.add(to);
  }
  
  // 获取顶点的邻居
  getNeighbors(vertex) {
    const neighbors = [];
    for (const edge of this.edges) {
      if (edge.from === vertex) {
        neighbors.push({ to: edge.to, weight: edge.weight });
      } else if (edge.to === vertex) {
        neighbors.push({ to: edge.from, weight: edge.weight });
      }
    }
    return neighbors;
  }
  
  // 获取所有顶点
  getVertices() {
    return Array.from(this.vertices);
  }
  
  // 打印图
  print() {
    for (const edge of this.edges) {
      console.log(`${edge.from} --${edge.weight}--> ${edge.to}`);
    }
  }
}

图的基本性质

1. 度(Degree)

顶点的度是与该顶点相连的边的数量。

// 计算顶点的度
function calculateDegree(graph, vertex) {
  if (graph instanceof AdjacencyMatrix) {
    const index = graph.vertices.indexOf(vertex);
    return graph.matrix[index].reduce((sum, weight) => sum + (weight > 0 ? 1 : 0), 0);
  } else if (graph instanceof AdjacencyList) {
    return graph.getNeighbors(vertex).length;
  }
}

// 计算所有顶点的度
function calculateAllDegrees(graph) {
  const degrees = {};
  const vertices = graph.getVertices ? graph.getVertices() : graph.vertices;
  
  for (const vertex of vertices) {
    degrees[vertex] = calculateDegree(graph, vertex);
  }
  
  return degrees;
}

2. 路径和连通性

路径(Path)

从一个顶点到另一个顶点的边序列。

// 检查是否存在路径
function hasPath(graph, start, end, visited = new Set()) {
  if (start === end) return true;
  
  visited.add(start);
  const neighbors = graph.getNeighbors(start);
  
  for (const neighbor of neighbors) {
    const neighborVertex = neighbor.to || neighbor;
    if (!visited.has(neighborVertex)) {
      if (hasPath(graph, neighborVertex, end, visited)) {
        return true;
      }
    }
  }
  
  return false;
}

// 查找所有路径
function findAllPaths(graph, start, end, path = [], visited = new Set()) {
  path.push(start);
  visited.add(start);
  
  if (start === end) {
    return [path.slice()];
  }
  
  const paths = [];
  const neighbors = graph.getNeighbors(start);
  
  for (const neighbor of neighbors) {
    const neighborVertex = neighbor.to || neighbor;
    if (!visited.has(neighborVertex)) {
      const newPaths = findAllPaths(graph, neighborVertex, end, path, visited);
      paths.push(...newPaths);
    }
  }
  
  path.pop();
  visited.delete(start);
  
  return paths;
}

连通性(Connectivity)

图中顶点之间的可达性。

// 检查图的连通性
function isConnected(graph) {
  const vertices = graph.getVertices ? graph.getVertices() : graph.vertices;
  if (vertices.length <= 1) return true;
  
  const start = vertices[0];
  const visited = new Set();
  
  // 从起始顶点开始DFS
  dfs(graph, start, visited);
  
  // 检查是否所有顶点都被访问
  return visited.size === vertices.length;
}

// 深度优先搜索
function dfs(graph, vertex, visited) {
  visited.add(vertex);
  const neighbors = graph.getNeighbors(vertex);
  
  for (const neighbor of neighbors) {
    const neighborVertex = neighbor.to || neighbor;
    if (!visited.has(neighborVertex)) {
      dfs(graph, neighborVertex, visited);
    }
  }
}

3. 环(Cycle)

图中包含重复顶点的路径。

// 检测环
function hasCycle(graph) {
  const visited = new Set();
  const recStack = new Set();
  
  const vertices = graph.getVertices ? graph.getVertices() : graph.vertices;
  
  for (const vertex of vertices) {
    if (!visited.has(vertex)) {
      if (dfsCycle(graph, vertex, visited, recStack)) {
        return true;
      }
    }
  }
  
  return false;
}

// DFS检测环
function dfsCycle(graph, vertex, visited, recStack) {
  visited.add(vertex);
  recStack.add(vertex);
  
  const neighbors = graph.getNeighbors(vertex);
  
  for (const neighbor of neighbors) {
    const neighborVertex = neighbor.to || neighbor;
    
    if (!visited.has(neighborVertex)) {
      if (dfsCycle(graph, neighborVertex, visited, recStack)) {
        return true;
      }
    } else if (recStack.has(neighborVertex)) {
      return true;
    }
  }
  
  recStack.delete(vertex);
  return false;
}

图的应用场景

1. 社交网络

// 社交网络图
class SocialNetwork {
  constructor() {
    this.users = new Map();
  }
  
  // 添加用户
  addUser(userId, name) {
    this.users.set(userId, {
      id: userId,
      name: name,
      friends: new Set(),
      posts: []
    });
  }
  
  // 添加好友关系
  addFriendship(user1, user2) {
    if (this.users.has(user1) && this.users.has(user2)) {
      this.users.get(user1).friends.add(user2);
      this.users.get(user2).friends.add(user1);
    }
  }
  
  // 获取好友列表
  getFriends(userId) {
    const user = this.users.get(userId);
    return user ? Array.from(user.friends) : [];
  }
  
  // 获取共同好友
  getCommonFriends(user1, user2) {
    const friends1 = new Set(this.getFriends(user1));
    const friends2 = new Set(this.getFriends(user2));
    
    return Array.from(friends1).filter(friend => friends2.has(friend));
  }
  
  // 计算社交距离
  getSocialDistance(user1, user2) {
    const visited = new Set();
    const queue = [{ userId: user1, distance: 0 }];
    
    while (queue.length > 0) {
      const { userId, distance } = queue.shift();
      
      if (userId === user2) {
        return distance;
      }
      
      if (!visited.has(userId)) {
        visited.add(userId);
        const friends = this.getFriends(userId);
        
        for (const friend of friends) {
          if (!visited.has(friend)) {
            queue.push({ userId: friend, distance: distance + 1 });
          }
        }
      }
    }
    
    return -1; // 不可达
  }
}

2. 网络拓扑

// 网络拓扑图
class NetworkTopology {
  constructor() {
    this.nodes = new Map();
    this.connections = [];
  }
  
  // 添加网络节点
  addNode(nodeId, type, capacity) {
    this.nodes.set(nodeId, {
      id: nodeId,
      type: type, // router, switch, server, client
      capacity: capacity,
      status: 'active'
    });
  }
  
  // 添加连接
  addConnection(from, to, bandwidth) {
    this.connections.push({
      from: from,
      to: to,
      bandwidth: bandwidth,
      status: 'active'
    });
  }
  
  // 检查网络连通性
  isNetworkConnected() {
    const nodes = Array.from(this.nodes.keys());
    if (nodes.length <= 1) return true;
    
    const visited = new Set();
    this.dfsNetwork(nodes[0], visited);
    
    return visited.size === nodes.length;
  }
  
  // 网络DFS
  dfsNetwork(nodeId, visited) {
    visited.add(nodeId);
    
    for (const connection of this.connections) {
      if (connection.status === 'active') {
        const nextNode = connection.from === nodeId ? connection.to : 
                        connection.to === nodeId ? connection.from : null;
        
        if (nextNode && !visited.has(nextNode)) {
          this.dfsNetwork(nextNode, visited);
        }
      }
    }
  }
  
  // 查找关键节点(割点)
  findCriticalNodes() {
    const criticalNodes = [];
    const nodes = Array.from(this.nodes.keys());
    
    for (const node of nodes) {
      // 临时移除节点
      const tempConnections = this.connections.filter(c => 
        c.from !== node && c.to !== node
      );
      
      // 检查连通性
      if (tempConnections.length > 0) {
        const visited = new Set();
        const remainingNodes = nodes.filter(n => n !== node);
        
        if (remainingNodes.length > 0) {
          this.dfsNetworkWithConnections(remainingNodes[0], visited, tempConnections);
          
          if (visited.size < remainingNodes.length) {
            criticalNodes.push(node);
          }
        }
      }
    }
    
    return criticalNodes;
  }
}

3. 地图导航

// 地图导航图
class NavigationGraph {
  constructor() {
    this.locations = new Map();
    this.roads = [];
  }
  
  // 添加地点
  addLocation(id, name, coordinates) {
    this.locations.set(id, {
      id: id,
      name: name,
      coordinates: coordinates
    });
  }
  
  // 添加道路
  addRoad(from, to, distance, time) {
    this.roads.push({
      from: from,
      to: to,
      distance: distance,
      time: time
    });
  }
  
  // 查找最短路径(按距离)
  findShortestPath(start, end) {
    const distances = new Map();
    const previous = new Map();
    const unvisited = new Set();
    
    // 初始化
    for (const location of this.locations.keys()) {
      distances.set(location, Infinity);
      unvisited.add(location);
    }
    distances.set(start, 0);
    
    while (unvisited.size > 0) {
      // 找到距离最小的未访问节点
      let current = null;
      let minDistance = Infinity;
      
      for (const location of unvisited) {
        if (distances.get(location) < minDistance) {
          minDistance = distances.get(location);
          current = location;
        }
      }
      
      if (current === null) break;
      
      unvisited.delete(current);
      
      if (current === end) break;
      
      // 更新邻居距离
      for (const road of this.roads) {
        if (road.from === current && unvisited.has(road.to)) {
          const newDistance = distances.get(current) + road.distance;
          if (newDistance < distances.get(road.to)) {
            distances.set(road.to, newDistance);
            previous.set(road.to, current);
          }
        }
      }
    }
    
    // 重建路径
    const path = [];
    let current = end;
    while (current !== null) {
      path.unshift(current);
      current = previous.get(current);
    }
    
    return {
      path: path,
      distance: distances.get(end)
    };
  }
}

图论的重要定理

1. 握手定理(Handshaking Lemma)

在任何图中,所有顶点的度数之和等于边数的两倍。

// 验证握手定理
function verifyHandshakingLemma(graph) {
  const degrees = calculateAllDegrees(graph);
  const totalDegree = Object.values(degrees).reduce((sum, degree) => sum + degree, 0);
  const edgeCount = graph.edges ? graph.edges.length : 
                   graph.vertices ? graph.vertices.reduce((sum, neighbors) => sum + neighbors.length, 0) / 2 : 0;
  
  console.log(`总度数: ${totalDegree}`);
  console.log(`边数: ${edgeCount}`);
  console.log(`边数的两倍: ${edgeCount * 2}`);
  console.log(`握手定理成立: ${totalDegree === edgeCount * 2}`);
  
  return totalDegree === edgeCount * 2;
}

2. 欧拉路径定理

图中存在欧拉路径当且仅当图是连通的且恰好有0个或2个奇数度顶点。

// 检查是否存在欧拉路径
function hasEulerPath(graph) {
  if (!isConnected(graph)) return false;
  
  const degrees = calculateAllDegrees(graph);
  const oddDegreeCount = Object.values(degrees).filter(degree => degree % 2 === 1).length;
  
  return oddDegreeCount === 0 || oddDegreeCount === 2;
}

学习建议

  1. 掌握基本概念:理解顶点、边、度、路径等基本术语
  2. 熟悉表示方法:掌握邻接矩阵、邻接表、边列表的优缺点
  3. 实践算法:动手实现图的遍历、搜索算法
  4. 应用导向:结合实际问题学习图论的应用
  5. 数学基础:学习相关的数学理论,如组合数学、线性代数

图论是计算机科学的重要基础,掌握图论知识对于解决复杂问题非常有帮助。