算法之图算法

1、广度优先搜索:

package com.arithmetic.graph;
import java.util.LinkedList;
import java.util.Queue;
//定义一个邻接矩阵用于表示图的结构,0表示两个节点之间没有边,1表示有边连接。
//然后使用一个布尔数组visited来标记节点是否被访问过。
//breadthFirstSearch方法使用广度优先搜索算法遍历图,从指定的起始节点开始。
//使用一个队列queue来存储待访问的节点,首先将起始节点添加到队列中,并将其标记为已访问。
//然后,不断地从队列中取出一个节点并打印它,然后遍历该节点的邻居节点,如果邻居节点还未被访问过,则将其加入队列中,并标记为已访问。
//如此循环,直到队列为空。
//在main方法中,创建一个BreadthFirstSearch对象并调用breadthFirstSearch方法进行测试。
//注意,这只是一个示例,实际应用中可能需要更复杂的数据结构来表示图。
public class BreadthFirstSearchDemo {
    private int[][] adjacencyMatrix; // 图的邻接矩阵
    private boolean[] visited; // 用于标记节点是否被访问过

    public BreadthFirstSearchDemo(int[][] adjacencyMatrix) {
        this.adjacencyMatrix = adjacencyMatrix;
        visited = new boolean[adjacencyMatrix.length];
    }

    // 广度优先搜索算法
    public void breadthFirstSearch(int startNode) {
        Queue<Integer> queue = new LinkedList<>();
        queue.add(startNode);
        visited[startNode] = true;

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

            // 遍历当前节点的邻居节点
            for (int i = 0; i < adjacencyMatrix.length; i++) {
                if (adjacencyMatrix[currentNode][i] == 1 && !visited[i]) {
                    queue.add(i);
                    visited[i] = true;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[][] adjacencyMatrix = {
            {0, 1, 1, 0},
            {1, 0, 0, 1},
            {1, 0, 0, 1},
            {0, 1, 1, 0}
        };

        BreadthFirstSearchDemo bfs = new BreadthFirstSearchDemo(adjacencyMatrix);

        System.out.println("BFS traversal starting from node 0:");
        
        bfs.breadthFirstSearch(0);
    }
}

2、深度优先搜索:

package com.arithmetic.graph;
import java.util.Stack;
//使用邻接矩阵来表示图的结构,同时使用布尔数组visited来标记节点是否被访问过。
//depthFirstSearch方法使用深度优先搜索算法遍历图,从指定的起始节点开始。
//使用一个堆栈stack来存储待访问的节点,首先将起始节点压入栈中,并将其标记为已访问。
//然后,不断地从栈中弹出一个节点并打印它,然后遍历该节点的邻居节点,如果邻居节点还未被访问过,则将其压入栈中,并标记为已访问。
//如此循环,直到栈为空。
//在main方法中,创建一个DepthFirstSearch对象并调用depthFirstSearch方法进行测试。
//实际应用中可能需要更复杂的数据结构来表示图。
public class DepthFirstSearchDemo {
    private int[][] adjacencyMatrix; // 图的邻接矩阵
    private boolean[] visited; // 用于标记节点是否被访问过

    public DepthFirstSearchDemo(int[][] adjacencyMatrix) {
        this.adjacencyMatrix = adjacencyMatrix;
        visited = new boolean[adjacencyMatrix.length];
    }

    // 深度优先搜索算法
    public void depthFirstSearch(int startNode) {
        Stack<Integer> stack = new Stack<>();
        stack.push(startNode);
        visited[startNode] = true;

        while (!stack.isEmpty()) {
            int currentNode = stack.pop();
            System.out.print(currentNode + " ");

            // 遍历当前节点的邻居节点
            for (int i = 0; i < adjacencyMatrix.length; i++) {
                if (adjacencyMatrix[currentNode][i] == 1 && !visited[i]) {
                    stack.push(i);
                    visited[i] = true;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[][] adjacencyMatrix = {
            {0, 1, 1, 0},
            {1, 0, 0, 1},
            {1, 0, 0, 1},
            {0, 1, 1, 0}
        };

        DepthFirstSearchDemo dfs = new DepthFirstSearchDemo(adjacencyMatrix);

        System.out.println("DFS traversal starting from node 0:");
        
        dfs.depthFirstSearch(0);
    }
}

3、最短路径算法:

package com.arithmetic.graph;
import java.util.*;
//定义一个 dijkstra 方法来实现Dijkstra算法。
//它接受一个邻接矩阵表示的图和起始节点作为参数,并返回起始节点到其他节点的最短路径数组。
//在 dijkstra 方法中,首先初始化距离数组和访问标记数组。
//然后,使用循环来选择距离最小且未访问的节点,并更新与该节点直接相邻的节点的最短距离。最后,返回最短路径数组。

//在主函数中,定义了一个邻接矩阵来表示图,并使用 dijkstra 方法计算起始节点 0 到其他节点的最短路径,并打印结果。
//一个简单示例,实际的实现可能需要更多的错误处理和性能优化。
//还有其他最短路径算法(如Floyd-Warshall算法)的实现方式,可以根据具体的需求选择合适的算法。
public class DijkstraAlgorithmDemo {
    private static final int INF = Integer.MAX_VALUE; // 代表无穷大的值

    public int[] dijkstra(int[][] graph, int start) {
        int n = graph.length;
        int[] dist = new int[n];
        boolean[] visited = new boolean[n];
        
        Arrays.fill(dist, INF);
        dist[start] = 0;

        for (int i = 0; i < n - 1; i++) {
            int minDist = INF;
            int minNode = -1;

            // 选择距离最小且未访问的节点
            for (int j = 0; j < n; j++) {
                if (!visited[j] && dist[j] < minDist) {
                    minDist = dist[j];
                    minNode = j;
                }
            }

            visited[minNode] = true;

            // 更新与当前节点直接相邻的节点的最短距离
            for (int j = 0; j < n; j++) {
                if (!visited[j] && graph[minNode][j] != INF && dist[minNode] + graph[minNode][j] < dist[j]) {
                    dist[j] = dist[minNode] + graph[minNode][j];
                }
            }
        }

        return dist;
    }

    public static void main(String[] args) {
        int[][] graph = {
            {0, 3, INF, 7},
            {3, 0, 2, INF},
            {INF, 2, 0, 1},
            {7, INF, 1, 0}
        };

        DijkstraAlgorithmDemo dijkstra = new DijkstraAlgorithmDemo();
        int[] dist = dijkstra.dijkstra(graph, 0);

        System.out.println("最短路径:");
        for (int i = 0; i < dist.length; i++) {
            System.out.println("0 -> " + i + ": " + dist[i]);
        }
    }
}

4、贪心算法:

package com.arithmetic.graph;

import java.util.Arrays;
//贪心算法
//在给定硬币面额的情况下,找零钱的最少数量。
//先将硬币面额按照升序进行排序,然后从最大面额的硬币开始,选择尽可能多的该面额硬币进行找零,直到目标金额为0。
//最后返回找到的硬币数量。
public class GreedyAlgorithmDemo {

    public static int findMinCoins(int[] coins, int amount) {
        Arrays.sort(coins); // 将硬币面额按照升序排序
        int count = 0;

        for (int i = coins.length - 1; i >= 0; i--) {
            while (amount >= coins[i]) { // 当目标金额大于等于当前面额时
                amount -= coins[i]; // 目标金额减去当前面额
                count++; // 零钱数量加1
            }
        }

        return count;
    }

    public static void main(String[] args) {
        int[] coins = {1, 5, 10, 25}; // 面额为1、5、10、25的硬币
        int amount = 36; // 目标金额
        int minCoins = findMinCoins(coins, amount);
        System.out.println("最少需要的硬币数量为:" + minCoins);
    }
}

5、最小生成树算法1:

package com.arithmetic.graph;
import java.util.*;
//最小生成树算法用于在一个连通的无向加权图中,找到一个权重和最小的生成树(包含所有顶点且没有环)。
//在KruskalMSTDemo 中,使用Kruskal算法来查找最小生成树的权重。
//在这种算法中,需要提供一个图的表示以及图中各个边的权重。
//在主函数中,定义一个图的表示以及图中各个边的权重,并调用相应的算法来查找最小生成树的权重。
public class KruskalMSTDemo {
    class Edge implements Comparable<Edge> {
        int src, dest, weight;
        
        public int compareTo(Edge compareEdge) {
            return this.weight - compareEdge.weight;
        }
    };
    
    private int V, E; // 图的顶点数和边数
    private Edge[] edges; // 图的所有边
    
    public KruskalMSTDemo(int V, int E) {
        this.V = V;
        this.E = E;
        
        edges = new Edge[E];
        for (int i = 0; i < E; i++) {
            edges[i] = new Edge();
        }
    }
    
    private int find(int[] parent, int i) {
        if (parent[i] == -1) {
            return i;
        }
        return find(parent, parent[i]);
    }
    
    private void union(int[] parent, int x, int y) {
        int xset = find(parent, x);
        int yset = find(parent, y);
        parent[xset] = yset;
    }
    
    public void kruskalMST() {
        Edge[] result = new Edge[V];
        int e = 0;
        int i = 0;
        for (i = 0; i < V; i++) {
            result[i] = new Edge();
        }
        
        Arrays.sort(edges);
        
        int[] parent = new int[V];
        Arrays.fill(parent, -1);
        
        i = 0;
        while (e < V-1) {
            Edge nextEdge = edges[i++];
            
            int x = find(parent, nextEdge.src);
            int y = find(parent, nextEdge.dest);
            
            if (x != y) {
                result[e++] = nextEdge;
                union(parent, x, y);
            }
        }
        
        printMST(result);
    }
    
    private void printMST(Edge[] result) {
        System.out.println("Edge   Weight");
        for (int i = 0; i < V-1; i++) {
            System.out.println(result[i].src + " - " + result[i].dest + "    " + result[i].weight);
        }
    }
    
    public static void main(String[] args) {
        int V = 5; // 图的顶点数
        int E = 7; // 图的边数
        
        KruskalMSTDemo mst = new KruskalMSTDemo(V, E);
        
        mst.edges[0].src = 0;
        mst.edges[0].dest = 1;
        mst.edges[0].weight = 7;
        
        mst.edges[1].src = 0;
        mst.edges[1].dest = 3;
        mst.edges[1].weight = 5;
        
        mst.edges[2].src = 1;
        mst.edges[2].dest = 2;
        mst.edges[2].weight = 8;
        
        mst.edges[3].src = 1;
        mst.edges[3].dest = 3;
        mst.edges[3].weight = 9;
        
        mst.edges[4].src = 1;
        mst.edges[4].dest = 4;
        mst.edges[4].weight = 7;
        
        mst.edges[5].src = 2;
        mst.edges[5].dest = 4;
        mst.edges[5].weight = 5;
        
        mst.edges[6].src = 3;
        mst.edges[6].dest = 4;
        mst.edges[6].weight = 15;
        
        mst.kruskalMST();
    }
}

6、最小生成树算法2:

package com.arithmetic.graph;
import java.util.*;
//最小生成树算法用于在一个连通的无向加权图中,找到一个权重和最小的生成树(包含所有顶点且没有环)。
//在PrimMSTDemo中,使用Prim算法来查找最小生成树的权重。
//在这种算法中,需要提供一个图的表示以及图中各个边的权重。
//在主函数中,定义一个图的表示以及图中各个边的权重,并调用相应的算法来查找最小生成树的权重。
public class PrimMSTDemo {
    private int V; // 图的顶点数
    private int[] parent; // 最小生成树的父节点数组
    private boolean[] visited; // 记录顶点是否被访问过
    private int[][] graph; // 图的邻接矩阵表示
    
    public PrimMSTDemo(int[][] graph) {
        this.V = graph.length;
        this.graph = graph;
        
        parent = new int[V];
        visited = new boolean[V];
        
        for (int i = 0; i < V; i++) {
            parent[i] = -1;
            visited[i] = false;
        }
    }
    
    public void primMST() {
        int[] key = new int[V]; // 记录顶点到最小生成树的最小权值
        Arrays.fill(key, Integer.MAX_VALUE);
        key[0] = 0;
        
        for (int count = 0; count < V-1; count++) {
            int u = minKey(key, visited);
            visited[u] = true;
            
            for (int v = 0; v < V; v++) {
                if (graph[u][v] != 0 && !visited[v] && graph[u][v] < key[v]) {
                    parent[v] = u;
                    key[v] = graph[u][v];
                }
            }
        }
        
        printMST();
    }
    
    private int minKey(int[] key, boolean[] visited) {
        int min = Integer.MAX_VALUE;
        int minIndex = -1;
        
        for (int v = 0; v < V; v++) {
            if (!visited[v] && key[v] < min) {
                min = key[v];
                minIndex = v;
            }
        }
        
        return minIndex;
    }
    
    private void printMST() {
        System.out.println("Edge   Weight");
        for (int i = 1; i < V; i++) {
            System.out.println(parent[i] + " - " + i + "    " + graph[i][parent[i]]);
        }
    }
    
    public static void main(String[] args) {
        int[][] graph = {
            {0, 2, 0, 6, 0},
            {2, 0, 3, 8, 5},
            {0, 3, 0, 0, 7},
            {6, 8, 0, 0, 9},
            {0, 5, 7, 9, 0}
        };
        
        PrimMSTDemo mst = new PrimMSTDemo(graph);
        mst.primMST();
    }
}

7、最小生成树算法3:

package com.arithmetic.graph;
import java.util.*;
//最小生成树算法用于在一个连通的无向加权图中,找到一个权重和最小的生成树(包含所有顶点且没有环)。
//在PrimAlgorithmDemo 中,使用Prim算法来查找最小生成树的总权重。
//在这种算法中,需要提供一个图的表示以及图中各个边的权重。
//在主函数中,定义一个图的表示以及图中各个边的权重,并调用相应的算法来查找最小生成树的总权重。

//最小生成树算法可以用来构建网络通信中的最优拓扑结构,以便实现最小的传输代价或者最小的延迟。
//在铁路规划中,可以用来确定线路间的最优连接方式,以便降低建设成本、减少运输时间.
//在石油、天然气、水等管道系统的布线中,可以帮助确定最优的管道连接方式,以减少材料和能耗成本。
//在电力传输网络中,可以帮助确定电力线路的最佳布局,以最小化能源损耗和传输成本。
//在交通规划中,可以用来确定交通网络中的最优路径,以减少交通拥堵和减少行车时间。
//在电路设计中,可以用来确定元器件之间的连接方式,以降低电路的复杂度和成本。
//在城市规划中,可以用来确定街道和道路的布局,以最小化交通拥堵和提高城市运行效率。


class PrimAlgorithmDemo {
    public int prim(int[][] graph) {
        int n = graph.length;
        int[] dist = new int[n];
        boolean[] visited = new boolean[n];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[0] = 0;

        int minWeight = 0;

        for (int i = 0; i < n; i++) {
            int u = -1;
            for (int j = 0; j < n; j++) {
                if (!visited[j] && (u == -1 || dist[j] < dist[u])) {
                    u = j;
                }
            }

            visited[u] = true;
            minWeight += dist[u];

            for (int j = 0; j < n; j++) {
                if (!visited[j] && graph[u][j] != 0 && graph[u][j] < dist[j]) {
                    dist[j] = graph[u][j];
                }
            }
        }

        return minWeight;
    }

    public static void main(String[] args) {
        int[][] graph = {
            {0, 2, 0, 6, 0},
            {2, 0, 3, 8, 5},
            {0, 3, 0, 0, 7},
            {6, 8, 0, 0, 9},
            {0, 5, 7, 9, 0}
        };

        PrimAlgorithmDemo prim = new PrimAlgorithmDemo();
        int minWeight = prim.prim(graph);

        System.out.println("最小生成树的总权重: " + minWeight);
    }
}

 

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值