自学内容网 自学内容网

数据结构第一弹-图

大家好,今天和大家一起学习一下数据结构中的图~

图(Graph)是一种非线性的数据结构,它由节点(也称为顶点,Vertices)和边(Edges)组成。图可以用来表示各种关系网络,如社交网络、交通网络、计算机网络等。图的灵活性使得它在许多领域中都有广泛的应用,包括但不限于算法设计、数据库系统、编译器优化以及机器学习。

1. 图的基本概念

1.1 节点与边

  • 节点(Vertex/Node): 图中的基本单位,代表一个实体。
  • (Edge): 连接两个节点的连线,表示这两个节点之间的某种关系。

1.2 图的类型

  • 无向图(Undirected Graph): 边没有方向性,如果存在一条从A到B的边,则也存在一条从B到A的边。
  • 有向图(Directed Graph): 边具有方向性,一条从A到B的边并不意味着存在一条从B到A的边。
  • 加权图(Weighted Graph): 每条边都关联有一个权重值,用于表示边上的成本或距离。
  • 连通图(Connected Graph): 在无向图中,任意两个顶点之间都存在路径;在有向图中,至少存在一个顶点能够到达其他所有顶点。
  • 完全图(Complete Graph): 每对不同的顶点之间都恰好有一条边相连。

1.3 常见术语

  • (Degree): 一个节点连接的边的数量。
  • 入度(In-degree): 在有向图中,指向该节点的边数。
  • 出度(Out-degree): 在有向图中,从该节点出发的边数。
  • 路径(Path): 一系列相邻节点组成的序列。
  • (Cycle): 一条起始节点和结束节点相同的路径。
  • 最短路径(Shortest Path): 两节点间所有可能路径中最短的一条。

2. 图的存储方式

图可以通过多种方式存储,其中最常见的两种是邻接矩阵和邻接表。

2.1 邻接矩阵

邻接矩阵是一个二维数组,用于表示图中各节点间的连接情况。如果A[i][j]为1,则表示节点i和节点j之间存在一条边;如果是0,则表示不存在边。对于加权图,可以用具体权重代替1。

public class AdjacencyMatrix {

    private final int V; // 顶点数量
    private int[][] adjMatrix; // 邻接矩阵
    public AdjacencyMatrix(int v) {
        V = v;
        adjMatrix = new int[V][V];
    }

    public void addEdge(int u, int v, int weight) {
        adjMatrix[u][v] = weight;
        if (u != v) { // 对于无向图
            adjMatrix[v][u] = weight;
        }
    }

    public void printMatrix() {
        for (int i = 0; i < V; i++) {
            for (int j = 0; j < V; j++) {
                System.out.print(adjMatrix[i][j] + " ");
            }
            System.out.println();
        }
    }
}

2.2 邻接表

邻接表使用链表或数组来存储每个节点的所有邻居节点。这种方式在稀疏图中更加高效。


import java.util.ArrayList;
import java.util.List;

public class AdjacencyList {
    private final int V; // 顶点数量
    private List<List<Integer>> adjList; // 邻接表

    public AdjacencyList(int v) {
        V = v;
        adjList = new ArrayList<>(V);
        for (int i = 0; i < V; ++i) {
            adjList.add(new ArrayList<>());
        }
    }

    public void addEdge(int u, int v) {
        adjList.get(u).add(v);
        if (u != v) { // 对于无向图
            adjList.get(v).add(u);
        }
    }


    public void printList() {
        for (int i = 0; i < V; i++) {
            System.out.print("Adjacency list of vertex " + i + ":");
            for (int j : adjList.get(i)) {
                System.out.print(" -> " + j);
            }
            System.out.println();
        }
    }
}

3. 图的遍历算法

图的遍历是指访问图中所有顶点的过程。常用的遍历方法有两种:深度优先搜索(DFS)和广度优先搜索(BFS)。

3.1 深度优先搜索(DFS)

DFS从一个给定的起点开始,尽可能深地探索每个分支,直到无法继续为止,然后回溯并尝试另一条路径。

import java.util.*;

public class DFS {
    private boolean[] visited;

    public DFS(int vertices) {
        visited = new boolean[vertices];
    }

    public void dfs(AdjacencyList graph, int start) {
        Stack<Integer> stack = new Stack<>();
        stack.push(start);

        while (!stack.isEmpty()) {
            int s = stack.pop();

            if (!visited[s]) {
                System.out.print(s + " ");
                visited[s] = true;
            }

            for (int n : graph.adjList.get(s)) {
                if (!visited[n]) {
                    stack.push(n);
                }
            }
        }
    }
}

3.2 广度优先搜索(BFS)

BFS则从一个给定的起点开始,逐层向外扩展,先访问离起点最近的所有节点,然后再访问更远一层的节点。

import java.util.*;

public class BFS {
    private boolean[] visited;
    public BFS(int vertices) {
        visited = new boolean[vertices];
    }

    public void bfs(AdjacencyList graph, int start) {
        Queue<Integer> queue = new LinkedList<>();
        queue.add(start);
        visited[start] = true;

        while (!queue.isEmpty()) {
            int s = queue.poll();
            System.out.print(s + " ");

            for (int n : graph.adjList.get(s)) {
                if (!visited[n]) {
                    queue.add(n);
                    visited[n] = true;
                }
            }
        }
    }
}

4. 图的应用实例

4.1 社交网络分析

社交网络可以看作是有向图,用户作为节点,好友关系作为边。通过图论算法,我们可以计算用户的影响力、社区检测等。

4.2 路径规划

在地图应用中,城市作为节点,道路作为边。利用Dijkstra算法或A*算法,可以找到两点之间的最短路径。

import java.util.*;

public class Dijkstra {
    private static final int INF = Integer.MAX_VALUE;

    public static int[] dijkstra(AdjacencyList graph, int start) {
        int n = graph.V;
        int[] dist = new int[n];
        Arrays.fill(dist, INF);
        dist[start] = 0;
        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
        pq.offer(new int[]{start, 0});

        while (!pq.isEmpty()) {
            int[] current = pq.poll();
            int u = current[0];
            if (dist[u] < current[1]) continue;
            for (int v : graph.adjList.get(u)) {
                if (dist[u] + 1 < dist[v]) { // 假设所有边的权重都是1
                    dist[v] = dist[u] + 1;
                    pq.offer(new int[]{v, dist[v]});
                }
            }
        }

        return dist;
    }
}

4.3 数据库索引

在数据库中,图可以用来表示表之间的关系。例如,在关系型数据库中,外键约束可以形成一张图,帮助优化查询性能。

4.4 编译器优化

编译器在进行代码优化时,可以将程序转换成控制流图(CFG),通过对图的操作来识别冗余代码、循环不变量等,从而提高程序效率。

图作为一种强大的数据结构,提供了丰富的表达能力和灵活的处理机制。无论是简单的关系表示还是复杂的网络分析,图都能提供有效的解决方案,欢迎大家一起在评论区讨论~


原文地址:https://blog.csdn.net/fengxiaotao_cool/article/details/144300839

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!