Java数据结构算法-图形算法

引言

图形算法主要涉及到图这种数据结构的操作和处理。图由顶点(节点)和边组成,边连接顶点。图论中的算法可以应用于各种场景,如社交网络分析、网络路由、最短路径问题等。

算法介绍

1. 深度优先搜索(DFS)

简介

深度优先搜索是一种用于遍历或搜索树或图的算法。这个算法会尽可能深地搜索树的分支。当节点v的所在边都已被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。

Java代码示例

import java.util.*;  
  
class Graph {  
    private int numVertices;  
    private LinkedList<Integer> adjLists[];  
  
    Graph(int vertices) {  
        numVertices = vertices;  
        adjLists = new LinkedList[vertices];  
        for (int i = 0; i < vertices; ++i) {  
            adjLists[i] = new LinkedList();  
        }  
    }  
  
    void addEdge(int src, int dest) {  
        adjLists[src].add(dest);  
    }  
  
    void DFS(int vertex) {  
        boolean visited[] = new boolean[numVertices];  
        DFSUtil(vertex, visited);  
    }  
  
    void DFSUtil(int vertex, boolean visited[]) {  
        visited[vertex] = true;  
        System.out.print(vertex + " ");  
  
        Iterator<Integer> iterator = adjLists[vertex].iterator();  
        while (iterator.hasNext()) {  
            int adj = iterator.next();  
            if (!visited[adj]) {  
                DFSUtil(adj, visited);  
            }  
        }  
    }  
  
    public static void main(String args[]) {  
        Graph graph = new Graph(4);  
        graph.addEdge(0, 1);  
        graph.addEdge(0, 2);  
        graph.addEdge(1, 2);  
        graph.addEdge(2, 0);  
        graph.addEdge(2, 3);  
        graph.addEdge(3, 3);  
  
        System.out.println("Depth First Traversal (starting from vertex 2):");  
        graph.DFS(2);  
    }  
}

优点

  1. 在某些情况下,DFS的时间复杂度可能比其他搜索算法更低,尤其是在图或树的结构较为简单时。
  2. DFS的空间复杂度相对较低,通常只需要存储当前路径上的节点信息。

缺点

  1. DFS可能会陷入无限循环,特别是在存在环的情况下,如果没有适当的终止条件,可能会导致时间复杂度无法估计。
  2. 如果图或树的结构非常复杂,DFS可能需要遍历大量节点,导致时间复杂度较高。
  3. DFS在某些情况下可能会使用大量的栈空间,尤其是在递归实现时,如果树的深度较大,可能会导致栈溢出的问题。

2. 广度优先搜索(BFS)

简介

广度优先搜索是另一种用于遍历或搜索树或图的算法。这个算法从根节点(或任意节点)开始,探索最近的节点,然后进一步探索下一层的节点,依此类推。

Java代码示例

import java.util.*;  
  
class Graph {  
    private int numVertices;  
    private LinkedList<Integer> adjLists[];  
  
    Graph(int vertices) {  
        numVertices = vertices;  
        adjLists = new LinkedList[vertices];  
        for (int i = 0; i < vertices; ++i) {  
            adjLists[i] = new LinkedList();  
        }  
    }  
  
    void addEdge(int src, int dest) {  
        adjLists[src].add(dest);  
    }  
  
    void BFS(int vertex) {  
        boolean visited[] = new boolean[numVertices];  
        LinkedList<Integer> queue = new LinkedList<Integer>();  
  
        visited[vertex] = true;  
        queue.add(vertex);  
  
        while (queue.size() != 0) {  
            vertex = queue.poll();  
            System.out.print(vertex + " ");  
  
            Iterator<Integer> iterator = adjLists[vertex].iterator();  
            while (iterator.hasNext()) {  
                int adj = iterator.next();  
                if (!visited[adj]) {  
                    visited[adj] = true;  
                    queue.add(adj);  
                }  
            }  
        }  
    }  
  
    public static void main(String args[]) {  
        Graph graph = new Graph(4);  
        graph.addEdge(0, 1);  
        graph.addEdge(0, 2);  
        graph.addEdge(1, 2);  
        graph.addEdge(2, 0);  
        graph.addEdge(2, 3);  
        graph.addEdge(3, 3);  
  
        System.out.println("Breadth First Traversal (starting from vertex 2):

优点

  1. BFS总是可以找到从起始节点到目标节点的最短路径(如果存在的话)。
  2. BFS的搜索过程是有序的,可以按照层次顺序遍历图或树的节点。

缺点

  1. BFS的盲目性较大,当目标节点距初始节点较远时,会产生许多无用节点,导致搜索效率降低。
  2. 在大型图或树中,BFS可能需要大量的内存来存储待访问的节点,特别是在最坏情况下,可能需要存储图或树中的所有节点。

3.Dijkstra算法

简介

Dijkstra算法是图论中的一个经典算法,用于解决带权有向图中单源最短路径问题。它计算从给定源节点到其他所有节点的最短路径。算法的主要思想是通过迭代的方式,每次从未访问的节点中选择一个距离源节点最近的节点,然后更新其相邻节点的距离值。

基本步骤

  1. 初始化距离数组dist[],将源节点到自身的距离设为0,其他节点到源节点的距离设为无穷大(或某个很大的数)。
  2. 创建一个未访问节点的集合Q,初始时包含图中所有节点。
  3. 从Q中选择一个距离最小的节点u,并将其从Q中移除。
  4. 对u的每个邻居节点v,如果通过u到达v的距离比当前已知的v的距离更短,则更新v的距离值。
  5. 重复步骤3和4,直到Q为空,即所有节点都已访问。

Java代码示例

 import java.util.*;  
  
class Graph {  
    private int numVertices;  
    private LinkedList<Edge> adjLists[];  
    private int minDistance[];  
    private Set<Integer> settled;  
  
    class Edge {  
        int dest, weight;  
        Edge(int dest, int weight) {  
            this.dest = dest;  
            this.weight = weight;  
        }  
    }  
  
    Graph(int vertices) {  
        numVertices = vertices;  
        adjLists = new LinkedList[vertices];  
        minDistance = new int[vertices];  
        settled = new HashSet<Integer>();  
  
        for (int i = 0; i < vertices; i++) {  
            adjLists[i] = new LinkedList<>();  
        }  
    }  
  
    void addEdge(int src, int dest, int weight) {  
        Edge edge = new Edge(dest, weight);  
        adjLists[src].add(edge);  
    }  
  
    void dijkstra(int src) {  
        for (int i = 0; i < numVertices; i++) {  
            minDistance[i] = Integer.MAX_VALUE;  
        }  
        minDistance[src] = 0;  
  
        PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> minDistance[a] - minDistance[b]);  
        pq.add(src);  
  
        while (!pq.isEmpty()) {  
            int u = pq.poll();  
  
            settled.add(u);  
  
            Iterator<Edge> i = adjLists[u].iterator();  
            while (i.hasNext()) {  
                Edge e = i.next();  
                int v = e.dest;  
                int weight = e.weight;  
  
                if (settled.contains(v) == false && minDistance[v] > minDistance[u] + weight) {  
                    minDistance[v] = minDistance[u] + weight;  
                    pq.add(v);  
                }  
            }  
        }  
  
        printSolution(minDistance);  
    }  
  
    void printSolution(int dist[]) {  
        System.out.println("Vertex \t\t Distance from Source");  
        for (int i = 0; i < numVertices; ++i) {  
            System.out.println(i + "\t\t" + minDistance[i]);  
        }  
    }  
  
    public static void main(String args[]) {  
        Graph g = new Graph(9);  
  
        g.addEdge(0, 1, 4);  
        g.addEdge(0, 7, 8);  
        g.addEdge(1, 2, 8);  
        g.addEdge(1, 7, 11);  
        g.addEdge(2, 3, 7);  
        g.addEdge(2, 8, 2);  
        g.addEdge(3, 4, 9);  
        g.addEdge(3, 5, 14);  
        g.addEdge(4, 5, 10);  
        g.addEdge(5, 6, 2);  
        g.addEdge(6, 7, 1);  
        g.addEdge(6, 8, 6);  
        g.addEdge(7, 8, 7);  
  
        g.dijkstra(0);  
    }  
}

优点

  1. Dijkstra算法能够找到从单个源点到其他所有顶点的最短路径。
  2. 算法实现相对简单,容易理解和实现。

缺点

  1. Dijkstra算法无法处理带有负权边的图,因为其在路径选择时采用了贪心策略,可能会忽略负权边导致的更短路径。
  2. 在大型图中,Dijkstra算法可能需要较长的运行时间,因为其时间复杂度与图中的节点数和边数有关。

总结

总的来说,每种算法都有其适用的场景和优缺点,选择哪种算法取决于具体的问题和需求。在实际应用中,需要根据问题的特点、图的大小和复杂性以及可用的计算资源来选择合适的算法。

  • 95
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旅人OranGe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值