ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【数据结构】图论入门 [打印本页]

作者: 一给    时间: 2024-6-22 13:01
标题: 【数据结构】图论入门
引入

数据的逻辑结构:
图的基本概念及术语

   图:G = ( V, E )
  V:顶点(数据元素)的有穷非空聚集
  E:边的有穷聚集
  图的类型界说

无向图:每条边都是无方向的


有向图:每条弧都是有方向的


完全图:任意两个点都有一条边相连
稀疏图:有很少的边或者弧的图(通常 m 远小于nlog(n))
稠密图:有较多的边或者弧的图(通常 m 大于nlog(n))
连通图:在无(有)向图G = (V,{E})中,若对任意两个顶点v、u,都存在v到u的路径,则称G是连通图(强连通图)
图的基本术语

图的存储结构

数组(毗邻矩阵)表现法

概述

建立一个顶点表(记录各个顶点信息)和一个毗邻矩阵(表现各个顶点之间的关系)
举例

无向图


详细形况根据顶点的值去建立顶点表
毗邻矩阵:
V1V2V3V4V5V101010V210101V301011V410100V501100 特点:
代码演示见下面遍历部分
有向图


毗邻矩阵:
v1v2v3v4v10110v20000v30001v41000 特点:
   网的毗邻矩阵就是将1用权值替换
  代码演示见下面遍历部分
优缺点

优点:
缺点:
毗邻表

顶点:按编号顺序将顶点数据存储在一维数组中
关联同一顶点的边(以顶点为尾的弧):用线性链表存储
举例

仍以上图为例
无向图:


特点:
代码演示见下面遍历部分
有向图:


特点:
代码演示见下面遍历部分
   毗邻矩阵与毗邻表的关系:
  1.接洽:毗邻表中每个链表对应于毗邻矩阵中的每一行,链表中结点个数即是一行中非零元素的个数
  2.区别:
  a.对于任意确定的无向图,毗邻矩阵是唯一的(行列号与顶点编号同等),但毗邻表不唯一(毗连次序与顶点编号无关)
b.毗邻矩阵的空间复杂度为O(n^2),而毗连表的空间复杂度为O(n+e)
  图的遍历

界说:从已给的连通图中某一顶点出发,沿着一些边访问图中所有的顶点,且每个顶点仅被访问一次,就叫做图的遍历,它是图的基本运算
实质:找每个顶点的毗邻点的过程
问题:由图的特点,图中可能出现回路,且图的任一顶点都可能与其他结点相遇,在访问完某个顶点之后可能会沿着某些边又回到了曾经访问过的顶点,怎么避免重复访问?
解决思路:设置辅助数组a[n],用来标志每个被访问过的顶点,初始状态都为0,当顶点i被访问,改a为1,防止被多次访问
深度优先搜索(DFS)

方法:

  • 在访问图中某一起始顶点v后,由v出发,访问它的任一毗邻顶点w1
  • 再由w1出发访问与w1毗邻,但还未被访问过的顶点w2
  • 然后再从w2出发进行雷同的访问…
  • 如此进行下去,直至到达所有的毗邻顶点都被访问过的顶点u为止
  • 接着退回一步退到前一次刚访问过的顶点,看是否还有其他没有被访问的毗邻顶点
  • 如果有则访问此顶点,之后再从此顶点出发,进行与之前雷同的访问
  • 如果没有就再退回一步进行搜索,重复上述过程,直到连通图中所有顶点都被访问过为止
留意:

  • 稠密图适于在毗邻矩阵上进行深度遍历
  • 稀疏图适于在毗连表上进行深度遍历
对于毗邻矩阵的代码演示:
  1. public class GraphAdjacencyMatrix {
  2.     private int V; // 顶点的数量
  3.     private int[][] matrix; // 邻接矩阵
  4.     private boolean[] visited;
  5.     // 构造函数
  6.     public GraphAdjacencyMatrix(int v) {
  7.         V = v;
  8.         matrix = new int[v][v];
  9.         visited = new boolean[v];
  10.         for (int i = 0; i < v; i++) {
  11.             visited[i] = false;
  12.         }
  13.     }
  14.     // 添加边
  15.     public void addEdge(int v, int w, int weight) {
  16.         matrix[v][w] = weight; // 因为是无向图,所以需要添加两个方向的边
  17.         matrix[w][v] = weight;
  18.     }
  19.     //深度优先遍历
  20.     private void DFS(int v) {
  21.         visited[v] = true;
  22.         System.out.print(v + " ");
  23.         for (int i = 0; i < V; i++) {
  24.             if (matrix[v][i] == 1 && !visited[i]) {
  25.                 DFS(i);
  26.             }
  27.         }
  28.     }
  29.     // 遍历所有顶点(如果顶点未访问,则进行DFS)
  30.     public void DFSTraversal() {
  31.         for (int i = 0; i < V; i++) {
  32.             if (!visited[i]) {
  33.                 DFS(i); // 从顶点i开始DFS
  34.             }
  35.         }
  36.     }
  37.     // 打印图
  38.     public void printGraph() {
  39.         for (int i = 0; i < V; i++) {
  40.             for (int j = 0; j < V; j++) {
  41.                 if (matrix[i][j] == 0) {
  42.                     System.out.print("0 ");
  43.                 } else {
  44.                     System.out.print(matrix[i][j] + " ");
  45.                 }
  46.             }
  47.             System.out.println();
  48.         }
  49.     }
  50. }
复制代码
  1. public class linjiejuzhen {
  2.     public static void main(String[] args) {
  3.         GraphAdjacencyMatrix graph = new GraphAdjacencyMatrix(4);
  4.         graph.addEdge(0, 1, 10); // 添加边 0-1 权重为 10
  5.         graph.addEdge(0, 2, 6);
  6.         graph.addEdge(1, 2, 4);
  7.         graph.addEdge(2, 3, 1);
  8.         System.out.println("Adjacency Matrix:");
  9.         graph.printGraph();
  10.         System.out.println("Depth First Traversal starting from vertex 0: ");
  11.         graph.DFSTraversal(); //0 1 2 3
  12.     }
  13. }
复制代码
  1. Adjacency Matrix:
  2. 0 10 6 0
  3. 10 0 4 0
  4. 6 4 0 1
  5. 0 0 1 0
  6. Depth First Traversal starting from vertex 0:
  7. 0 1 2 3
复制代码
对于毗邻表代码演示:
  1. import java.util.Iterator;
  2. import java.util.LinkedList;
  3. public class DirectedGraphAdjacencyList {
  4.     private int V; // 顶点的数量
  5.     private LinkedList<Integer> adj[];
  6.     private boolean visited[]; // 邻接表
  7.     // 构造函数
  8.     public DirectedGraphAdjacencyList(int v) {
  9.         V = v;
  10.         adj = new LinkedList[v];
  11.         visited = new boolean[v];
  12.         for (int i = 0; i < v; i++) {
  13.             adj[i] = new LinkedList<>();
  14.             visited[i] = false;
  15.         }
  16.     }
  17.     // 添加边
  18.     public void addEdge(int v, int w) {
  19.         adj[v].add(w); // 添加从顶点v到顶点w的有向边
  20.     }
  21.     // 打印图
  22.     public void printGraph() {
  23.         for (int i = 0; i < V; i++) {
  24.             System.out.print("Vertex " + i + ":");
  25.             Iterator<Integer> it = adj[i].iterator();
  26.             while (it.hasNext()) {
  27.                 System.out.print(" -> " + it.next());
  28.             }
  29.             System.out.println();
  30.         }
  31.     }
  32.     private void DFS(int v) {
  33.         visited[v] = true;
  34.         System.out.print(v + " ");
  35.         Iterator<Integer> i = adj[v].listIterator();
  36.         while (i.hasNext()) {
  37.             int n = i.next();
  38.             if (!visited[n]) {
  39.                 DFS(n); // 递归访问未访问的邻接顶点
  40.             }
  41.         }
  42.     }
  43.     // 遍历所有顶点执行DFS
  44.     public void DFSTraversal() {
  45.         for (int i = 0; i < V; i++) {
  46.             if (!visited[i]) {
  47.                 DFS(i); // 从顶点i开始DFS
  48.             }
  49.         }
  50.     }
  51. }
复制代码
  1. public class DirectedGraphAdjacency {
  2.     public static void main(String[] args) {
  3.         DirectedGraphAdjacencyList graph = new DirectedGraphAdjacencyList(6);
  4.         // 添加有向边
  5.         graph.addEdge(5, 0);
  6.         graph.addEdge(5, 3);
  7.         graph.addEdge(4, 0);
  8.         graph.addEdge(4, 1);
  9.         graph.addEdge(2, 3);
  10.         graph.addEdge(3, 1);
  11.         graph.addEdge(1, 3);
  12.         System.out.println("Adjacency List Representation of Directed Graph:");
  13.         graph.printGraph();
  14.         System.out.println("Depth First Traversal starting from vertex 0: ");
  15.         graph.DFSTraversal(); //0 1 3 2 4 5
  16.     }
  17. }
复制代码
  1. Adjacency List Representation of Directed Graph:
  2. Vertex 0:
  3. Vertex 1: -> 3
  4. Vertex 2: -> 3
  5. Vertex 3: -> 1
  6. Vertex 4: -> 0 -> 1
  7. Vertex 5: -> 0 -> 3
  8. Depth First Traversal starting from vertex 0:
  9. 0 1 3 2 4 5
复制代码
广度优先搜索(BFS)

方法:
从图的某一结点出发,首先依次访问该结点的所有毗邻结点 Vi1、Vi2……Vin,再按这些顶点被访问的先后次序依次访问与他们相毗邻的所有未被访问的顶点。重复此过程,直至所有顶点均被访问为止
对于毗邻矩阵的代码演示
  1. import java.util.LinkedList;
  2. import java.util.Queue;
  3. public class DirectedGraphAdjacencyMatrix {
  4.     private int V; // 顶点的数量
  5.     private int[][] matrix; // 邻接矩阵
  6.     private boolean[] visited;
  7.     // 构造函数
  8.     public DirectedGraphAdjacencyMatrix(int v) {
  9.         V = v;
  10.         matrix = new int[v][v];
  11.         visited = new boolean[v];
  12.         // 初始化矩阵,所有元素都设置为0,表示没有边
  13.         for (int i = 0; i < v; i++) {
  14.             for (int j = 0; j < v; j++) {
  15.                 matrix[i][j] = 0;
  16.             }
  17.             visited[i] = false;
  18.         }
  19.     }
  20.     // 添加边
  21.     public void addEdge(int v, int w, int weight) {
  22.         matrix[v][w] = weight; // 只在矩阵的对应位置添加边的权重
  23.     }
  24.     // 打印图
  25.     public void printGraph() {
  26.         for (int i = 0; i < V; i++) {
  27.             for (int j = 0; j < V; j++) {
  28.                 if (matrix[i][j] == 0) {
  29.                     System.out.print(" 0 ");
  30.                 } else {
  31.                     System.out.print(" " + matrix[i][j] + " ");
  32.                 }
  33.             }
  34.             System.out.println();
  35.         }
  36.     }
  37.     //广度优先搜索
  38.     public void BFS(int start) {
  39.         Queue<Integer> queue = new LinkedList<>();
  40.         visited[start] = true; // 标记起始顶点为已访问
  41.         queue.add(start); // 将起始顶点添加到队列中
  42.         while (!queue.isEmpty()) {
  43.             int v = queue.poll(); // 从队列中取出一个顶点
  44.             System.out.print(v + " ");
  45.             for (int i = 0; i < V; i++) {
  46.                 if (matrix[v][i] != 0 && !visited[i]) {
  47.                     visited[i] = true; // 标记邻接顶点为已访问
  48.                     queue.add(i); // 将邻接顶点添加到队列中
  49.                 }
  50.             }
  51.         }
  52.     }
  53. }
复制代码
  1. public class linjiejuzhenYou {
  2.     public static void main(String[] args) {
  3.         DirectedGraphAdjacencyMatrix graph = new DirectedGraphAdjacencyMatrix(4);
  4.         graph.addEdge(0, 1, 10); // 添加有向边 0->1 权重为 10
  5.         graph.addEdge(0, 2, 6);
  6.         graph.addEdge(1, 2, 4);
  7.         graph.addEdge(1, 3, 1);
  8.         graph.addEdge(2, 3, 7);
  9.         System.out.println("Directed Adjacency Matrix:");
  10.         graph.printGraph();
  11.         System.out.println("Breadth First Traversal starting from vertex 0: ");
  12.         graph.BFS(0); //0 1 2 3
  13.     }
  14. }
复制代码
  1. Directed Adjacency Matrix:
  2. 0  10  6  0
  3. 0  0  4  1
  4. 0  0  0  7
  5. 0  0  0  0
  6. Breadth First Traversal starting from vertex 0:
  7. 0 1 2 3
复制代码
对于毗邻表的代码演示
  1. import java.util.Iterator;
  2. import java.util.LinkedList;
  3. import java.util.Queue;
  4. public class UndirectedGraphAdjacencyList {
  5.     private int V; // 顶点的数量
  6.     private LinkedList<Integer> adj[]; // 邻接表
  7.     private boolean[] visited;
  8.     // 构造函数
  9.     public UndirectedGraphAdjacencyList(int v) {
  10.         V = v;
  11.         visited = new boolean[V];
  12.         adj = new LinkedList[v];
  13.         for (int i = 0; i < v; i++) {
  14.             adj[i] = new LinkedList<>();
  15.             visited[i] = false;
  16.         }
  17.     }
  18.     // 添加边
  19.     public void addEdge(int v, int w) {
  20.         adj[v].add(w); // 添加从v到w的边
  21.         adj[w].add(v); // 因为是无向图,所以需要添加从w到v的边
  22.     }
  23.     // 打印图
  24.     public void printGraph() {
  25.         for (int i = 0; i < V; i++) {
  26.             System.out.print("Vertex " + i + ":");
  27.             Iterator<Integer> it = adj[i].iterator();
  28.             while (it.hasNext()) {
  29.                 System.out.print(" -> " + it.next());
  30.             }
  31.             System.out.println();
  32.         }
  33.     }
  34.     public void BFS(int start) {
  35.         Queue<Integer> queue = new LinkedList<>();
  36.         visited[start] = true; // 标记起始顶点为已访问
  37.         queue.add(start); // 将起始顶点添加到队列中
  38.         while (!queue.isEmpty()) {
  39.             int v = queue.poll(); // 从队列中取出一个顶点
  40.             System.out.print(v + " ");
  41.             Iterator<Integer> i = adj[v].listIterator();
  42.             while (i.hasNext()) {
  43.                 int n = i.next();
  44.                 if (!visited[n]) {
  45.                     visited[n] = true; // 标记邻接顶点为已访问
  46.                     queue.add(n); // 将邻接顶点添加到队列中
  47.                 }
  48.             }
  49.         }
  50.     }
  51. }
复制代码
  1. public class UndirectedGraphAdjacency {
  2.     public static void main(String[] args) {
  3.         UndirectedGraphAdjacencyList graph = new UndirectedGraphAdjacencyList(4);
  4.         graph.addEdge(0, 1); // 添加边 0-1
  5.         graph.addEdge(0, 2);
  6.         graph.addEdge(1, 2);
  7.         graph.addEdge(2, 3);
  8.         System.out.println("Adjacency List Representation of Undirected Graph:");
  9.         graph.printGraph();
  10.         System.out.println("Breadth First Traversal starting from vertex 0: ");
  11.         graph.BFS(0); //0 1 2 3
  12.     }
  13. }
复制代码
  1. Adjacency List Representation of Undirected Graph:
  2. Vertex 0: -> 1 -> 2
  3. Vertex 1: -> 0 -> 2
  4. Vertex 2: -> 0 -> 1 -> 3
  5. Vertex 3: -> 2
  6. Breadth First Traversal starting from vertex 0:
  7. 0 1 2 3
复制代码
二者搜索的算法分析

时间复杂度:
毗邻矩阵:
对于毗邻矩阵表现的图,时间复杂度重要受两个因素影响:

  • 矩阵大小:毗邻矩阵的大小为




    欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4