最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java圖論的兩個基本概念之有向圖與無向圖詳解

 更新時間:2026年03月24日 11:39:40   作者:Zhu_S?W  
圖論是數(shù)學(xué)的一個基本分支,涉及對圖研究,圖是復(fù)雜數(shù)據(jù)結(jié)構(gòu)的可視化表示,有助于理解不同實體之間的關(guān)系,這篇文章主要介紹了Java圖論的兩個基本概念之有向圖與無向圖的相關(guān)資料,需要的朋友可以參考下

圖(Graph)是計算機科學(xué)中一種重要的非線性數(shù)據(jù)結(jié)構(gòu),廣泛應(yīng)用于社交網(wǎng)絡(luò)、地圖導(dǎo)航、任務(wù)調(diào)度等領(lǐng)域。本文將使用Java語言深入講解圖論中的兩個基本概念:有向圖和無向圖。

什么是圖?

圖由兩個基本元素組成:

  • 頂點(Vertex/Node):圖中的節(jié)點,代表對象

  • 邊(Edge):連接兩個頂點,代表對象之間的關(guān)系

數(shù)學(xué)表示:G = (V, E),其中V是頂點集合,E是邊集合。

無向圖(Undirected Graph)

概念與特點

無向圖中的邊沒有方向,表示對稱的雙向關(guān)系。如果頂點A和頂點B之間存在一條邊,那么可以從A到達B,也可以從B到達A。

實際應(yīng)用

  • 社交網(wǎng)絡(luò):微信好友關(guān)系(互為好友)

  • 交通網(wǎng)絡(luò):城市間的雙向道路

  • 協(xié)作關(guān)系:項目團隊成員之間的合作關(guān)系

  • 網(wǎng)絡(luò)拓撲:局域網(wǎng)中設(shè)備的連接關(guān)系

Java實現(xiàn):鄰接表方式

import java.util.*;
?
/**
 * 無向圖的實現(xiàn)(使用鄰接表)
 */
public class UndirectedGraph {
    // 使用HashMap存儲圖,key為頂點,value為鄰接頂點列表
    private Map<String, List<String>> adjList;
    
    public UndirectedGraph() {
        this.adjList = new HashMap<>();
    }
    
    /**
     * 添加頂點
     */
    public void addVertex(String vertex) {
        adjList.putIfAbsent(vertex, new ArrayList<>());
    }
    
    /**
     * 添加邊(無向邊,需要雙向添加)
     */
    public void addEdge(String v1, String v2) {
        // 確保兩個頂點都存在
        addVertex(v1);
        addVertex(v2);
        
        // 添加雙向邊
        adjList.get(v1).add(v2);
        adjList.get(v2).add(v1);
    }
    
    /**
     * 移除邊
     */
    public void removeEdge(String v1, String v2) {
        List<String> v1Neighbors = adjList.get(v1);
        List<String> v2Neighbors = adjList.get(v2);
        
        if (v1Neighbors != null) {
            v1Neighbors.remove(v2);
        }
        if (v2Neighbors != null) {
            v2Neighbors.remove(v1);
        }
    }
    
    /**
     * 移除頂點
     */
    public void removeVertex(String vertex) {
        // 移除所有與該頂點相連的邊
        List<String> neighbors = adjList.get(vertex);
        if (neighbors != null) {
            for (String neighbor : new ArrayList<>(neighbors)) {
                removeEdge(vertex, neighbor);
            }
        }
        // 移除頂點
        adjList.remove(vertex);
    }
    
    /**
     * 獲取頂點的度(連接的邊的數(shù)量)
     */
    public int getDegree(String vertex) {
        List<String> neighbors = adjList.get(vertex);
        return neighbors != null ? neighbors.size() : 0;
    }
    
    /**
     * 獲取鄰接頂點
     */
    public List<String> getNeighbors(String vertex) {
        return adjList.getOrDefault(vertex, new ArrayList<>());
    }
    
    /**
     * 深度優(yōu)先搜索(DFS)
     */
    public void dfs(String start) {
        Set<String> visited = new HashSet<>();
        dfsHelper(start, visited);
    }
    
    private void dfsHelper(String vertex, Set<String> visited) {
        visited.add(vertex);
        System.out.print(vertex + " ");
        
        for (String neighbor : getNeighbors(vertex)) {
            if (!visited.contains(neighbor)) {
                dfsHelper(neighbor, visited);
            }
        }
    }
    
    /**
     * 廣度優(yōu)先搜索(BFS)
     */
    public void bfs(String start) {
        Set<String> visited = new HashSet<>();
        Queue<String> queue = new LinkedList<>();
        
        visited.add(start);
        queue.offer(start);
        
        while (!queue.isEmpty()) {
            String vertex = queue.poll();
            System.out.print(vertex + " ");
            
            for (String neighbor : getNeighbors(vertex)) {
                if (!visited.contains(neighbor)) {
                    visited.add(neighbor);
                    queue.offer(neighbor);
                }
            }
        }
    }
    
    /**
     * 打印圖結(jié)構(gòu)
     */
    public void display() {
        System.out.println("無向圖結(jié)構(gòu):");
        for (Map.Entry<String, List<String>> entry : adjList.entrySet()) {
            System.out.println(entry.getKey() + " -> " + entry.getValue());
        }
    }
}

無向圖使用示例

public class UndirectedGraphDemo {
    public static void main(String[] args) {
        UndirectedGraph graph = new UndirectedGraph();
        
        // 構(gòu)建社交網(wǎng)絡(luò)
        graph.addEdge("Alice", "Bob");
        graph.addEdge("Alice", "Charlie");
        graph.addEdge("Bob", "David");
        graph.addEdge("Charlie", "David");
        graph.addEdge("David", "Eve");
        
        // 顯示圖結(jié)構(gòu)
        graph.display();
        
        System.out.println("\n各頂點的度:");
        System.out.println("Alice的度: " + graph.getDegree("Alice"));
        System.out.println("David的度: " + graph.getDegree("David"));
        
        System.out.println("\n深度優(yōu)先搜索(從Alice開始):");
        graph.dfs("Alice");
        
        System.out.println("\n\n廣度優(yōu)先搜索(從Alice開始):");
        graph.bfs("Alice");
    }
}

有向圖(Directed Graph)

概念與特點

有向圖中的邊具有方向性,從一個頂點指向另一個頂點。邊<A, B>表示從A到B的單向關(guān)系,不代表可以從B到A。

實際應(yīng)用

  • 微博關(guān)注:用戶A關(guān)注用戶B,但B不一定關(guān)注A

  • 網(wǎng)頁鏈接:網(wǎng)頁間的超鏈接關(guān)系

  • 任務(wù)依賴:項目中任務(wù)的先后順序

  • 交通系統(tǒng):單行道網(wǎng)絡(luò)

  • 課程prerequisite:課程的先修關(guān)系

Java實現(xiàn):鄰接表方式

import java.util.*;
?
/**
 * 有向圖的實現(xiàn)(使用鄰接表)
 */
public class DirectedGraph {
    private Map<String, List<String>> adjList;
    
    public DirectedGraph() {
        this.adjList = new HashMap<>();
    }
    
    /**
     * 添加頂點
     */
    public void addVertex(String vertex) {
        adjList.putIfAbsent(vertex, new ArrayList<>());
    }
    
    /**
     * 添加有向邊(從v1指向v2)
     */
    public void addEdge(String from, String to) {
        addVertex(from);
        addVertex(to);
        
        // 只添加單向邊
        adjList.get(from).add(to);
    }
    
    /**
     * 移除邊
     */
    public void removeEdge(String from, String to) {
        List<String> neighbors = adjList.get(from);
        if (neighbors != null) {
            neighbors.remove(to);
        }
    }
    
    /**
     * 移除頂點
     */
    public void removeVertex(String vertex) {
        // 移除從該頂點出發(fā)的所有邊
        adjList.remove(vertex);
        
        // 移除指向該頂點的所有邊
        for (List<String> neighbors : adjList.values()) {
            neighbors.remove(vertex);
        }
    }
    
    /**
     * 獲取出度(從該頂點出發(fā)的邊數(shù))
     */
    public int getOutDegree(String vertex) {
        List<String> neighbors = adjList.get(vertex);
        return neighbors != null ? neighbors.size() : 0;
    }
    
    /**
     * 獲取入度(指向該頂點的邊數(shù))
     */
    public int getInDegree(String vertex) {
        int count = 0;
        for (List<String> neighbors : adjList.values()) {
            if (neighbors.contains(vertex)) {
                count++;
            }
        }
        return count;
    }
    
    /**
     * 獲取鄰接頂點(出邊指向的頂點)
     */
    public List<String> getNeighbors(String vertex) {
        return adjList.getOrDefault(vertex, new ArrayList<>());
    }
    
    /**
     * 拓撲排序(Kahn算法)
     * 適用于有向無環(huán)圖(DAG)
     */
    public List<String> topologicalSort() {
        List<String> result = new ArrayList<>();
        Map<String, Integer> inDegree = new HashMap<>();
        Queue<String> queue = new LinkedList<>();
        
        // 計算所有頂點的入度
        for (String vertex : adjList.keySet()) {
            inDegree.put(vertex, getInDegree(vertex));
        }
        
        // 將入度為0的頂點加入隊列
        for (Map.Entry<String, Integer> entry : inDegree.entrySet()) {
            if (entry.getValue() == 0) {
                queue.offer(entry.getKey());
            }
        }
        
        // BFS處理
        while (!queue.isEmpty()) {
            String vertex = queue.poll();
            result.add(vertex);
            
            // 減少鄰接頂點的入度
            for (String neighbor : getNeighbors(vertex)) {
                inDegree.put(neighbor, inDegree.get(neighbor) - 1);
                if (inDegree.get(neighbor) == 0) {
                    queue.offer(neighbor);
                }
            }
        }
        
        // 如果結(jié)果包含所有頂點,說明沒有環(huán)
        if (result.size() != adjList.size()) {
            System.out.println("圖中存在環(huán),無法進行拓撲排序!");
            return new ArrayList<>();
        }
        
        return result;
    }
    
    /**
     * 檢測是否存在環(huán)(使用DFS)
     */
    public boolean hasCycle() {
        Set<String> visited = new HashSet<>();
        Set<String> recStack = new HashSet<>();
        
        for (String vertex : adjList.keySet()) {
            if (hasCycleHelper(vertex, visited, recStack)) {
                return true;
            }
        }
        return false;
    }
    
    private boolean hasCycleHelper(String vertex, Set<String> visited, 
                                   Set<String> recStack) {
        if (recStack.contains(vertex)) {
            return true; // 發(fā)現(xiàn)環(huán)
        }
        if (visited.contains(vertex)) {
            return false;
        }
        
        visited.add(vertex);
        recStack.add(vertex);
        
        for (String neighbor : getNeighbors(vertex)) {
            if (hasCycleHelper(neighbor, visited, recStack)) {
                return true;
            }
        }
        
        recStack.remove(vertex);
        return false;
    }
    
    /**
     * 深度優(yōu)先搜索
     */
    public void dfs(String start) {
        Set<String> visited = new HashSet<>();
        dfsHelper(start, visited);
    }
    
    private void dfsHelper(String vertex, Set<String> visited) {
        visited.add(vertex);
        System.out.print(vertex + " ");
        
        for (String neighbor : getNeighbors(vertex)) {
            if (!visited.contains(neighbor)) {
                dfsHelper(neighbor, visited);
            }
        }
    }
    
    /**
     * 打印圖結(jié)構(gòu)
     */
    public void display() {
        System.out.println("有向圖結(jié)構(gòu):");
        for (Map.Entry<String, List<String>> entry : adjList.entrySet()) {
            System.out.println(entry.getKey() + " -> " + entry.getValue());
        }
    }
}

有向圖使用示例

public class DirectedGraphDemo {
    public static void main(String[] args) {
        DirectedGraph graph = new DirectedGraph();
        
        // 構(gòu)建課程依賴關(guān)系圖
        graph.addEdge("數(shù)據(jù)結(jié)構(gòu)", "算法");
        graph.addEdge("離散數(shù)學(xué)", "數(shù)據(jù)結(jié)構(gòu)");
        graph.addEdge("離散數(shù)學(xué)", "算法");
        graph.addEdge("程序設(shè)計", "數(shù)據(jù)結(jié)構(gòu)");
        graph.addEdge("算法", "人工智能");
        graph.addEdge("數(shù)據(jù)結(jié)構(gòu)", "數(shù)據(jù)庫");
        
        // 顯示圖結(jié)構(gòu)
        graph.display();
        
        System.out.println("\n各頂點的入度和出度:");
        System.out.println("數(shù)據(jù)結(jié)構(gòu) - 入度: " + graph.getInDegree("數(shù)據(jù)結(jié)構(gòu)") + 
                         ", 出度: " + graph.getOutDegree("數(shù)據(jù)結(jié)構(gòu)"));
        System.out.println("算法 - 入度: " + graph.getInDegree("算法") + 
                         ", 出度: " + graph.getOutDegree("算法"));
        
        System.out.println("\n檢測環(huán):");
        System.out.println("是否存在環(huán): " + graph.hasCycle());
        
        System.out.println("\n拓撲排序(課程學(xué)習(xí)順序):");
        List<String> order = graph.topologicalSort();
        System.out.println(order);
        
        System.out.println("\n深度優(yōu)先搜索(從離散數(shù)學(xué)開始):");
        graph.dfs("離散數(shù)學(xué)");
    }
}

鄰接矩陣實現(xiàn)

除了鄰接表,圖還可以用鄰接矩陣表示,特別適合稠密圖。

/**
 * 使用鄰接矩陣實現(xiàn)的圖(支持有向圖和無向圖)
 */
public class GraphMatrix {
    private int[][] matrix;
    private Map<String, Integer> vertexIndex;
    private Map<Integer, String> indexVertex;
    private int vertexCount;
    private boolean isDirected;
    
    public GraphMatrix(int maxVertices, boolean isDirected) {
        this.matrix = new int[maxVertices][maxVertices];
        this.vertexIndex = new HashMap<>();
        this.indexVertex = new HashMap<>();
        this.vertexCount = 0;
        this.isDirected = isDirected;
    }
    
    /**
     * 添加頂點
     */
    public void addVertex(String vertex) {
        if (!vertexIndex.containsKey(vertex)) {
            vertexIndex.put(vertex, vertexCount);
            indexVertex.put(vertexCount, vertex);
            vertexCount++;
        }
    }
    
    /**
     * 添加邊
     */
    public void addEdge(String v1, String v2) {
        addVertex(v1);
        addVertex(v2);
        
        int index1 = vertexIndex.get(v1);
        int index2 = vertexIndex.get(v2);
        
        matrix[index1][index2] = 1;
        
        // 如果是無向圖,需要添加反向邊
        if (!isDirected) {
            matrix[index2][index1] = 1;
        }
    }
    
    /**
     * 檢查是否存在邊
     */
    public boolean hasEdge(String v1, String v2) {
        Integer index1 = vertexIndex.get(v1);
        Integer index2 = vertexIndex.get(v2);
        
        if (index1 == null || index2 == null) {
            return false;
        }
        
        return matrix[index1][index2] == 1;
    }
    
    /**
     * 打印鄰接矩陣
     */
    public void display() {
        System.out.println("鄰接矩陣:");
        System.out.print("    ");
        for (int i = 0; i < vertexCount; i++) {
            System.out.printf("%-8s", indexVertex.get(i));
        }
        System.out.println();
        
        for (int i = 0; i < vertexCount; i++) {
            System.out.printf("%-4s", indexVertex.get(i));
            for (int j = 0; j < vertexCount; j++) {
                System.out.printf("%-8d", matrix[i][j]);
            }
            System.out.println();
        }
    }
}

有向圖 vs 無向圖對比

特性無向圖有向圖
邊的表示(v1, v2) 無序?qū)?/td><v1, v2> 有序?qū)?/td>
方向性雙向,對稱關(guān)系單向,非對稱關(guān)系
度的概念度(Degree)入度和出度
最大邊數(shù)n(n-1)/2n(n-1)
存儲開銷鄰接矩陣對稱鄰接矩陣不對稱
特有算法最小生成樹拓撲排序、強連通分量

圖的表示方法選擇

鄰接表 vs 鄰接矩陣

鄰接表

  • 空間復(fù)雜度:O(V + E)

  • 適合稀疏圖(邊少)

  • 遍歷某個頂點的鄰接點快

  • 判斷兩點是否相鄰較慢

鄰接矩陣

  • 空間復(fù)雜度:O(V²)

  • 適合稠密圖(邊多)

  • 判斷兩點是否相鄰快O(1)

  • 浪費空間存儲不存在的邊

常用圖算法

遍歷算法

  • 深度優(yōu)先搜索(DFS):遞歸或棧實現(xiàn)

  • 廣度優(yōu)先搜索(BFS):隊列實現(xiàn)

最短路徑算法

  • Dijkstra算法:單源最短路徑(非負權(quán)重)

  • Bellman-Ford算法:單源最短路徑(可處理負權(quán)重)

  • Floyd-Warshall算法:所有頂點對之間的最短路徑

有向圖特有算法

  • 拓撲排序:有向無環(huán)圖的線性排序

  • 強連通分量:Kosaraju算法、Tarjan算法

無向圖特有算法

  • 最小生成樹:Kruskal算法、Prim算法

  • 連通性檢測:并查集

性能優(yōu)化建議

  • 使用泛型:讓圖結(jié)構(gòu)更靈活,支持不同類型的頂點

  • 權(quán)重邊:可以擴展邊的數(shù)據(jù)結(jié)構(gòu),存儲權(quán)重信息

  • 線程安全:多線程環(huán)境下使用ConcurrentHashMap

  • 內(nèi)存優(yōu)化:大規(guī)模圖可以考慮使用位圖或壓縮存儲

總結(jié)

有向圖和無向圖是圖論的基礎(chǔ),掌握它們的Java實現(xiàn)對于解決復(fù)雜的網(wǎng)絡(luò)問題至關(guān)重要。選擇合適的圖類型和數(shù)據(jù)結(jié)構(gòu),能夠讓算法更高效:

  • 對稱關(guān)系用無向圖(社交、網(wǎng)絡(luò)拓撲)

  • 非對稱關(guān)系用有向圖(依賴、關(guān)注、鏈接)

  • 稀疏圖用鄰接表

  • 稠密圖用鄰接矩陣

希望本文能幫助你深入理解圖的概念和Java實現(xiàn),為學(xué)習(xí)更高級的圖算法打下堅實基礎(chǔ)!

到此這篇關(guān)于Java圖論的兩個基本概念之有向圖與無向圖的文章就介紹到這了,更多相關(guān)Java圖論有向圖與無向圖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Springboot-Starter造輪子之自動鎖組件lock-starter實現(xiàn)

    Springboot-Starter造輪子之自動鎖組件lock-starter實現(xiàn)

    這篇文章主要為大家介紹了Springboot-Starter造輪子之自動鎖組件lock-starter實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • Java中Minio的基本使用詳解

    Java中Minio的基本使用詳解

    這篇文章主要介紹了Java中Minio的基本使用詳解,MinIO 是一個基于Apache License v2.0開源協(xié)議的對象存儲服務(wù),它兼容亞馬遜S3云存儲服務(wù)接口,非常適合于存儲大容量非結(jié)構(gòu)化的數(shù)據(jù),例如圖片、視頻、日志文件、備份數(shù)據(jù)和容器/虛擬機鏡像等,需要的朋友可以參考下
    2024-01-01
  • Java 并發(fā)編程的可見性、有序性和原子性

    Java 并發(fā)編程的可見性、有序性和原子性

    這篇文章主要介紹了Java 并發(fā)編程的可見性、有序性和原子性的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java并發(fā)編程,感興趣的朋友可以了解下。
    2020-11-11
  • Spring-MVC異步請求之Servlet異步處理

    Spring-MVC異步請求之Servlet異步處理

    這篇文章主要介紹了Spring-MVC異步請求之Servlet異步處理,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • 詳解Maven 搭建spring boot多模塊項目(附源碼)

    詳解Maven 搭建spring boot多模塊項目(附源碼)

    這篇文章主要介紹了詳解Maven 搭建spring boot多模塊項目(附源碼),具有一定的參考價值,有興趣的可以了解一下
    2017-09-09
  • spring boot系列之集成測試(推薦)

    spring boot系列之集成測試(推薦)

    這篇文章主要介紹了spring boot系列集成測試,需要的朋友可以參考下
    2018-03-03
  • Spring?Boot整合log4j2日志配置的詳細教程

    Spring?Boot整合log4j2日志配置的詳細教程

    這篇文章主要介紹了SpringBoot項目中整合Log4j2日志框架的步驟和配置,包括常用日志框架的比較、配置參數(shù)介紹、Log4j2配置詳解以及使用步驟,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-02-02
  • 關(guān)于SpringBoot獲取IOC容器中注入的Bean(推薦)

    關(guān)于SpringBoot獲取IOC容器中注入的Bean(推薦)

    本文通過實例代碼給大家詳解了springboot獲取ioc容器中注入的bean問題,非常不錯,具有一定的參考借鑒價值,需要的朋友參考下吧
    2018-05-05
  • 幾種常見mybatis分頁實現(xiàn)方式

    幾種常見mybatis分頁實現(xiàn)方式

    這篇文章主要介紹了幾種常見mybatis分頁實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • DoytoQuery中的查詢映射方案詳解

    DoytoQuery中的查詢映射方案詳解

    這篇文章主要為大家介紹了DoytoQuery中的查詢映射方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12

最新評論

安化县| 和平区| 大名县| 门头沟区| 洪湖市| 衢州市| 阿拉善盟| 上犹县| 克东县| 富源县| 平江县| 张家界市| 定结县| 昌宁县| 南郑县| 松桃| 岱山县| 龙南县| 桐柏县| 临城县| 格尔木市| 潮安县| 黎平县| 葫芦岛市| 修文县| 濮阳县| 札达县| 海丰县| 会昌县| 汝城县| 泸定县| 南丰县| 双牌县| 盐山县| 蕲春县| 南溪县| 武宣县| 兴安盟| 古交市| 含山县| 龙江县|