數據結構與算法:圖形結構

2020-12-27 TechWeb

ͼ

圖形結構是一種比樹形結構更複雜的非線性結構。在樹形結構中,結點間具有分支層次關係,每一層上的結點只能和上一層中的至多一個結點相關,但可能和下一層的多個結點相關。而在圖形結構中,任意兩個結點之間都可能相關,即結點之間的鄰接關係可以是任意的。

因此,圖形結構被用於描述各種複雜的數據對象,在自然科學、社會科學和人文科學等許多領域有著非常廣泛的應用 。圖形結構在計算機科學、人工智慧、電子線路分析、最短路徑尋找、工程計劃、化學化合物分析統計力學、遺傳學、控制論語言學和社會科學等方面均有不同程度的應用可以這樣說,圖形結構在所有數據結構中應用最為廣泛。如在地鐵站中的線路圖:

圖的定義

圖是一種數據結構,其中節點可以具有零個或多個相鄰元素,兩個節點的連接稱之為邊,節點在圖形結構中也被稱為頂點,一個頂點到另一個頂點的經過的的線路稱為路徑。

圖形結構有3種類型:無向圖、有向圖、帶權圖 無向圖:頂點A與頂點B之間的邊是無方向的,可以從A到B,也可以從B到A 有向圖:頂點A與頂點B之間的邊是有方向的,可以從A到B,但不可以從B到A 帶權圖:頂點A與頂點B之間的邊是帶有屬性的,如A到B的 距離。 圖的表達方式

圖的表達方式有兩種:鄰接矩陣(使用二維數組)和鄰接表(使用數組+鍊表)

鄰接矩陣

鄰接矩陣是表示圖形中各頂點之間的關係,矩陣的行和列對應各頂點,坐標位置上的值對於它們之間的關係,1為連接, 0為沒有連接。在程序中用二維數組來實現。

鄰接表

鄰接表只關係存在的邊,不需要去為不存在的邊分配空間,因此比鄰接矩陣來說,避免了不必要的空間浪費。在程序中用數組+鍊表的形式實現,數組存儲對應的頂點,鍊表存儲該頂點連接的所有頂點。

圖的搜索算法

圖形結構基礎屬性和方法

以下的代碼演示都是以鄰接矩陣表達方式來實現的

//圖形結構(鄰接矩陣) class Graph {      //存儲圖中所有頂點     private List vertexes;     //圖形結構的鄰接矩陣     private int[][] matrix;     //各頂點訪問情況,true為已訪問,false為未訪問     private boolean[] visited;      /**      * 根據傳入的頂點信息生成矩陣      * @param s      */     public Graph(String s[]) {         vertexes = new ArrayList<>();         for (String vertex : s){             vertexes.add(vertex);         }         matrix = new int[s.length][s.length];     }      /**      * 將倆個頂點連接,即生成邊      * @param index1 頂點在集合中的索引      * @param index2      */     public void connect(int index1, int index2){         if (index1 < 0 || index1 > matrix.length || index2 < 0 || index2 > matrix.length){             throw new RuntimeException("該頂點未存在");         }         //將新的鄰接添加的鄰接矩陣中         matrix[index1][index2] = 1;         matrix[index2][index1] = 1;     }      /**      * 展示鄰接矩陣      */     public void showGraphMatrix(){         for (int arr[] : matrix){             System.out.println(Arrays.toString(arr));         }     }          /**      * 獲取頂點在鄰接矩陣對應行row中的第一個鄰接頂點下標      * @param row      * @return 當有鄰接頂點時返回鄰接頂點下標,沒有則返回-1      */     public int getFirstNeighbor(int row){         for(int i =0; i<matrix.length; i++){             if (matrix[row][i] != 0){                 return i;             }         }         return -1;     }      /**      * 獲取頂點在鄰接矩陣對於行row中col列的下一個鄰接頂點      * @param row      * @param col      * @return 當有鄰接頂點時返回鄰接頂點下標,沒有則返回-1      */     public int getNeighbor(int row, int col){         for (int i=col+1; i<matrix.length; i++){             if (matrix[row][i] != 0){                 return i;             }         }         return -1;     } }  深度優先搜索

深度優先搜索屬於圖算法的一種,英文縮寫為DFS即Depth First Search.其過程簡要來說是對每一個可能的分支路徑深入到不能再深入為止,而且每個節點只能訪問一次。這樣的訪問策略是優先往縱向進行深入挖掘,而不是對一個頂點的所有鄰接頂點進行橫線訪問。簡單來說就是一條路走到死,不行再掉頭。

思路:從當前頂點選一個與之連接而未訪問過的頂點,將當前節點往該鄰接頂點移動,如果鄰接頂點沒有未訪問的,則回溯到上一個頂點位置,繼續該步驟。直到所有頂點都訪問過。

往鄰接但未訪問過的頂點移動

鄰接頂點沒有未訪問的,進行回溯,直到遇到未訪問的鄰接頂點

當所有頂點都被訪問過時,退出算法

下面是深度優先搜索的過程動畫

代碼演示

public void dsf(){     visited = new boolean[vertexes.size()];     //以在集合中下標為0的頂點,進行深度搜索     dsf(visited, 0); }  /**  * 深度優先搜索  * @param visited  * @param row  */ public void dsf(boolean[] visited, int row){     //輸出當前頂點     System.out.print(vertexes.get(row) + " -> ");     //將當前頂點設為已訪問     visited[row] = true;     //獲取當前頂點的鄰接頂點下標     int index = getFirstNeighbor(row);     //如果當前頂點有鄰接頂點則進行深度搜索     while (index != -1){         //當鄰接頂點未訪問時,則遞歸遍歷         if (visited[index] != true){             dsf(visited, index);         }         //當鄰接頂點已訪問時,則尋找另一個鄰接頂點         index = getNeighbor(row, index);     } }  寬度優先搜索

寬度優先搜索算法(又稱廣度優先搜索)是最簡便的圖的搜索算法之一,這一算法也是很多重要的圖的算法的原型。Dijkstra單源最短路徑算法和Prim最小生成樹算法都採用了和寬度優先搜索類似的思想。其別名又叫BFS,屬於一種盲目搜尋法,目的是系統地展開並檢查圖中的所有節點,以找尋結果。換句話說,它並不考慮結果的可能位置,徹底地搜索整張圖,直到找到結果為止。

寬度優先搜索算法類似於一個分層搜索的過程,寬度優先搜索算法需要一個隊列以保持訪問過頂點的順序,以便按這個順序來訪問這些頂點的鄰接頂點。

思路:依次訪問當前頂點的鄰接頂點,並按訪問順序將這些鄰接頂點存儲在隊列中,噹噹前頂點的所有鄰接頂點都被訪問後,從隊列中彈出一個頂點,以該頂點為當前頂點繼續該步驟,直到所有頂點都被訪問過。

依次訪問當前頂點的所有鄰接頂點,並把這些鄰接頂點按訪問順序存儲在隊列中

當前頂點沒有未訪問的鄰接頂點,從隊列中彈出一個頂點,以該彈出頂點繼續訪問未訪問的鄰接頂點

注意,雖然圖中的頂點都已經訪問過了,但還是要等隊列中的所有頂點彈出訪問後,算法才結束

下面時寬度優先搜索的過程動畫

代碼演示

public void bfs(){     visited = new boolean[vertexes.size()];     ////以在集合中下標為0的頂點,進行廣度優先搜索     bfs(visited, 0); }  /**  * 廣度優先搜索  * @param visited  * @param row  */ public void bfs(boolean[] visited, int row){     //創建隊列,存儲遍歷鄰接頂點的順序     LinkedList queue = new LinkedList();     //輸出當前頂點     System.out.print(vertexes.get(row) + " -> ");     //將當前頂點設為已訪問     visited[row] = true;     //將當前頂點加入隊列中     queue.add(row);     //當隊列不為空時,即有未搜索的鄰接頂點,進行搜索     while (!queue.isEmpty()){         //按順序從隊列中彈出鄰接頂點下標         int last = (Integer)queue.removeFirst();         //獲取該彈出頂點的鄰接頂點下標         int index = getFirstNeighbor(last);         //當彈出頂點有鄰接頂點時,進行廣度搜索         while(index != -1){             //當鄰接頂點未訪問時             if(visited[index] != true){                 //輸出該鄰接頂點                 System.out.print(vertexes.get(index) + " -> ");                 //把該鄰接頂點設為已訪問                 visited[index] = true;                 //將該鄰接頂點加入隊列                 queue.addLast(index);             }             //繼續尋找彈出頂點的另一個鄰接頂點             index = getNeighbor(last, index);         }     } } 

完整演示代碼

public class GraphDemo {     public static void main(String[] args) {         String[] s = {"A","B","C","D","E","F","G"};         Graph graph = new Graph(s);         //A-B A-C A-G A-F F-D F-E D-E E-G         graph.connect(0, 1);         graph.connect(0, 2);         graph.connect(0, 6);         graph.connect(0, 5);         graph.connect(5, 3);         graph.connect(5, 4);         graph.connect(3, 4);         graph.connect(4, 6);         graph.showGraphMatrix();          graph.dsf();//A -> B -> C -> F -> D -> E -> G ->          System.out.println();         graph.bfs();//A -> B -> C -> F -> G -> D -> E ->      } }  //圖形結構 class Graph {     //存儲圖中所有頂點     private List vertexes;     //圖形結構的鄰接矩陣     private int[][] matrix;     //各頂點訪問情況,true為已訪問,false為未訪問     private boolean[] visited;      /**      * 根據傳入的頂點信息生成矩陣      * @param s      */     public Graph(String s[]) {         vertexes = new ArrayList<>();         for (String vertex : s){             vertexes.add(vertex);         }         matrix = new int[s.length][s.length];     }      /**      * 將倆個頂點連接,即生成邊      * @param index1 頂點在集合中的索引      * @param index2      */     public void connect(int index1, int index2){         if (index1 < 0 || index1 > matrix.length || index2 < 0 || index2 > matrix.length){             throw new RuntimeException("該頂點未存在");         }         //將新的鄰接添加的鄰接矩陣中         matrix[index1][index2] = 1;         matrix[index2][index1] = 1;     }      /**      * 展示鄰接矩陣      */     public void showGraphMatrix(){         for (int arr[] : matrix){             System.out.println(Arrays.toString(arr));         }     }      public void dsf(){         visited = new boolean[vertexes.size()];         //以在集合中下標為0的頂點,進行深度優先搜索         dsf(visited, 0);     }      /**      * 深度優先搜索      * @param visited      * @param row      */     public void dsf(boolean[] visited, int row){         //輸出當前頂點         System.out.print(vertexes.get(row) + " -> ");         //將當前頂點設為已訪問         visited[row] = true;         //獲取當前頂點的鄰接頂點下標         int index = getFirstNeighbor(row);         //如果當前頂點有鄰接頂點則進行深度搜索         while (index != -1){             //當鄰接頂點未訪問時,則遞歸遍歷             if (visited[index] != true){                 dsf(visited, index);             }             //當鄰接頂點已訪問時,則尋找另一個鄰接頂點             index = getNeighbor(row, index);         }     }      public void bfs(){         visited = new boolean[vertexes.size()];         ////以在集合中下標為0的頂點,進行廣度優先搜索         bfs(visited, 0);     }      /**      * 廣度優先搜索      * @param visited      * @param row      */     public void bfs(boolean[] visited, int row){         //創建隊列,存儲遍歷鄰接頂點的順序         Queue queue = new ArrayDeque();         //輸出當前頂點         System.out.print(vertexes.get(row) + " -> ");         //將當前頂點設為已訪問         visited[row] = true;         //將當前頂點加入隊列中         queue.add(row);         //當隊列不為空時,即有未搜索的鄰接頂點,進行搜索         while (!queue.isEmpty()){             //按順序從隊列中彈出鄰接頂點下標             int last = (Integer)queue.poll();             //獲取該彈出頂點的鄰接頂點下標             int index = getFirstNeighbor(last);             //當彈出頂點有鄰接頂點時,進行廣度搜索             while(index != -1){                 //當鄰接頂點未訪問時                 if(visited[index] != true){                     //輸出該鄰接頂點                     System.out.print(vertexes.get(index) + " -> ");                     //把該鄰接頂點設為已訪問                     visited[index] = true;                     //將該鄰接頂點加入隊列                     queue.add(index);                 }                 //繼續尋找彈出頂點的另一個鄰接頂點                 index = getNeighbor(last, index);             }         }     }      /**      * 獲取頂點在鄰接矩陣對應行row中的第一個鄰接頂點下標      * @param row      * @return 當有鄰接頂點時返回鄰接頂點下標,沒有則返回-1      */     public int getFirstNeighbor(int row){         for(int i =0; i<matrix.length; i++){             if (matrix[row][i] != 0){                 return i;             }         }         return -1;     }      /**      * 獲取頂點在鄰接矩陣對於行row中col列的下一個鄰接頂點      * @param row      * @param col      * @return 當有鄰接頂點時返回鄰接頂點下標,沒有則返回-1      */     public int getNeighbor(int row, int col){         for (int i=col+1; i<matrix.length; i++){             if (matrix[row][i] != 0){                 return i;             }         }         return -1;     } }   

相關焦點

  • 數據結構與算法:圖形結構
    作者:Gofy出處:https://www.cnblogs.com/gaofei200/p/13849762.html圖圖形結構是一種比樹形結構更複雜的非線性結構。在樹形結構中,結點間具有分支層次關係,每一層上的結點只能和上一層中的至多一個結點相關,但可能和下一層的多個結點相關。而在圖形結構中,任意兩個結點之間都可能相關,即結點之間的鄰接關係可以是任意的。因此,圖形結構被用於描述各種複雜的數據對象,在自然科學、社會科學和人文科學等許多領域有著非常廣泛的應用 。
  • 藍盟IT外包,數據結構和算法:圖形結構
    圖表結構是比樹結構更複雜的非線性結構。 在樹結構中,節點之間有分支層次關係,各層次上的節點只與一個層次上的多個節點相關,但有可能只與下一層次上的多個節點相關。 在圖表結構中,任意兩個節點之間可能存在相關性。 也就是說,節點之間的相鄰關係是任意的。
  • 數據結構與算法之算法概述
    二、什麼是數據結構數據結構,對應的英文單詞是data structure,是數據的組織、管理和存儲格式,其使用目的是為了高效地訪問和修改數據。線性結構線性結構是最簡單的數據結構,包括數組、鍊表,以及由它們衍生出來的棧、隊列、哈希表。2.樹樹是相對複雜的數據結構,其中比較有代表性的是二叉樹,由它又衍生出了二叉堆之類的數據結構。3.圖圖是更為複雜的數據結構,因為在圖中會呈現出多對多的關聯關係。
  • 數據結構與算法(線性結構-動態數組)
    1.算法: 是用於解決特定問題的一系列的執行步驟。2.評價算法如何評判一個算法的好壞,一般從以下維度進行評估算法的優劣:1.正確性、可讀性、健壯性(對不合理的反應的解決能力)。2.時間複雜度:估算程序指令的執行次數(執行時間)。3.空間複雜度: 估算所需佔用的存儲空間。
  • 程式設計師必知的數據結構與算法基礎:線性表數據結構之數組
    數據結構包括數據對象集以及它們在計算機中的組織方式,即它們的邏輯結構和物理存儲結構,一般我們可以認為數據結構指的是一組數據的存儲結構。2. 算法就是操作數據的方法,即如何操作數據效率更高,更節省資源。這只是抽象的定義,我們來舉一個例子,你有一批貨物需要運走,你是找小轎車來運還是找卡車來運?
  • 神器VisuAlgo:通過動畫學習算法和數據結構
    VisuAlgo是由Steven Halim博士在2011年發布的一款可視化學習算法的工具,用於幫助其學生更好地理解數據結構和算法,可以讓學生按自己的步驟來學習。VisuAlgo不僅支持暫停、單步、回退等功能,演示算法的時候,還可查看算法代碼的執行過程。
  • 數據結構——排序算法
    歡迎關注轉發點讚留言數據結構研究排序算法有何意義?排序算法資料庫底層用的最多了。實際工作中排序在資料庫高頻出現,最常用有按時間升降排序等等。不過這些排序只需通過資料庫排序命令就可完成,不用自個去整。數據結構排序分為內部排序(排序在內存完成),外部排序( 數據太多無法全部加載到內存,需要藉助外部存儲)。
  • 數據結構和算法對python意味著什麼?
    數據結構和算法對於python而言是他的靈魂;程序是數據結構加上算法來實現的,對於任何一門程式語言都離不開數據結構和算法,但是對於python而言內置了基礎的數據結構如列表、字典、集合等,再加上眾多包,所以弱化了數據結構和算法的使用。
  • 快速入門數據結構和算法
    常見的排序算法是如何實現的?各有什麼優缺點?本文簡要分享算法基礎、常見的數據結構以及排序算法,給同學們帶來一堂數據結構和算法的基礎課。了解常見數據結構和算法,溝通沒有障礙。活學活用:遇到問題時知道要用什麼數據結構和算法去優化。
  • 如何提升數據結構方面的算法能力
    那麼怎麼提升數據結構方面的算法能力呢?我認為主要是從基礎和應用這兩方面著手。因為算法是基於某種選擇的數據結構的。對於算法的時間複雜度和空間複雜的的理解和計算,對於常見算法的掌握。數據結構知識和算法知識是我們實際解決解決問題的基元
  • 騰訊T4每天熬夜到凌晨,竟在寫數據結構與算法的源碼筆記
    數據結構和算法是程式設計師的內功心法和基本功。無論是人工智慧還是其它計算機科學領域,掌握紮實的數據結構和算法知識,往往會助力不少!今天給大家推薦一份不錯的數據結構與算法資源。全書內容淺顯易懂,利用大量且豐富的圖示與範例,詳解複雜的抽象理論,從最基本的數據結構概念開始說明,再以Java工具加以詮釋陣列結構、堆棧、鍊表、隊列、排序、查找等重要的概念,引領讀者抓住重點輕鬆進入數據結構的學習領域。每章重要理論均有範例實現,書中收錄了精華的演算法及程序的執行過程,在線閱讀或下載附有完整的範例程序原始碼,讀者可以依照學習進度做練習。
  • 我們到底該如何學習《數據結構與算法》
    前言:我們到底該不該學習算法與數據結構?1、真的應該學習這個問題本身就不是個問題,所有人都在強調數據結構與算法比較重要,但是好像平時也沒用到,無法直觀的去感受它的重要性,於是把學習重心放在了常見的哪些框架身上,似乎只要熟悉了哪些框架的API,編程就會所向披靡。
  • java數據結構系列——什麼是數據結構
    讓我用我的理解來告訴你,什麼是數據結構。概述數據結構是計算機組織、存儲數據的方式。簡單來說就是,數據按指定的規則進行存儲,從而得到一個有固定存儲格式的數據集合,就稱之為「數據結構」。常見的邏輯結構(和其介紹)如下:集合:同一集合之間的元素存在關係,集合之外的數據之間是沒有任何關係的。線性結構:元素之間存在一對一的關係。樹形結構:元素之間存在一對多的關係。圖形結構:元素之間存在多對多的關係。
  • 算法設計:數據結構-樹
    一、樹的概念 一個結點有一個前驅和多個後繼結點,這種數據結構是樹形結構1、順序存儲結構 與線性表的順序存儲類似,二叉樹的順序存儲結構一般也由一個一維數組來構成,二叉樹上的節點按某種規定的次序逐個保存到數組的各個單元中 二叉樹順序存儲結構的數據定義如下:#define MAXSIZE 100 //最大節點數typedef int DATA ; //元素類型typedef DATA seqBinTree
  • JAVA必須掌握的數據結構和算法
    常見的數據結構鍊表LinkedHashSet LinkedList 底層數據結構由鍊表和哈希表組成。數據的添加和刪除都較為方便,就是訪問比較耗費時間。數組ArrayList 訪問數據十分簡單,而添加和刪除數據比較耗工夫堆堆是一種圖的樹形結構,被用於實現「優先隊列",優先隊列是一種數據結構,可以自由添加數據,但取出數據時要從最小值開始按順序取出
  • 資料| 現代計算機常用數據結構和算法
    內容簡介本書對現代計算機常用數據結構和算法進行全面而深入的介紹。本書系統地介紹了常用的數據結構和計算機算法,精心設計和安排了全書內容,適用於各類層次的讀者。即使是初學計算機算法的讀者,也可以從本書中找到所需的資料。本書的每一章中給出一個算法、一種設計技術、一個應用領域或一個相關的話題。算法是以通俗的語言說明的,並以"偽代碼"的形式來設計。可以很容易地把它轉化為電腦程式用於有關的應用。其中用了260多幅圖來說明算法是如何工作的,並對所有算法都進行仔細、精確的運行時刻分析。算法儘量設計的易於理解,趣味性強。
  • 你了解計算機專業的數據結構嗎?
    數據結構是指相互之間存在一種或多種特定關係的數據元素的集合。通常情況下,精心選擇的數據結構可以帶來更高的運行或者存儲效率。數據結構往往同高效的檢索算法和索引技術有關。程序=數據結構+算法,數據結構屬於靜態的部分,算法的調用為動態部分。一、首先了解一些基本的數據結構概念,以便更好地去理解。
  • 資料|現代計算機常用數據結構和算法
    from=leiphonecolumn_res0824內容簡介本書對現代計算機常用數據結構和算法進行全面而深入的介紹。本書系統地介紹了常用的數據結構和計算機算法,精心設計和安排了全書內容,適用於各類層次的讀者。即使是初學計算機算法的讀者,也可以從本書中找到所需的資料。
  • 分享給 .NET 開發者的一本數據結構與算法入門書
    不管是為了面試還是為了提高編程技能,作為一名優秀的開發者,都應該對數據結構和算法有基本的了解。有很多關於學習數據結構和算法的書,但基本上都是基於 C/C++語言或 Java 語言的,基於 C 語言的電子書:《數據結構與算法:C語言實現的數據結構和算法。
  • 數據結構與算法在現實中毫無作用?那我們為什麼還要去學習?
    如果公司在日常工作中沒有用,為什麼公司會問與數據結構和算法有關的問題? 許多初學者和經驗豐富的程式設計師都避免學習數據結構和算法,因為它很複雜,而且他們認為現實生活中沒有使用上述所有內容。