數據結構:圖及其鄰接矩陣與鄰接表表示


六度空間理論

圖中兩個頂點若要聯系,最多通過6個結點便可以完成 。

基本概念

  • 圖用於表示“多對多”的關系。

  • 包含

  • 一組頂點:通常用V (Vertex) 表示頂點集合

  • 一組邊:通常用E (Edge) 表示邊的集合

  • 邊是頂點對:(v, w) E ,其中v, w V

  • 有向邊< v, w> 表示從v指向w的邊(單行線)

  • 不考慮重邊和自回路

    • 重邊:兩個頂點之間有兩條邊。
    • 自回路:一個頂點的邊指向自己。

抽象數據類型定義

  • 類型名稱:圖(Graph)
  • 數據對象集:G(V,E)由一個非空的有限頂點集合V和一個有限邊集合E組成。
  • 操作集:對於任意圖G  Graph,以及v  V, e  E
  • Graph Create():建立並返回空圖;
  • Graph InsertVertex(Graph G, Vertex v):將v插入G;
  • Graph InsertEdge(Graph G, Edge e):將e插入G;
  • void DFS(Graph G, Vertex v):從頂點v出發深度優先遍歷圖G;
  • void BFS(Graph G, Vertex v):從頂點v出發寬度優先遍歷圖G;
  • void ShortestPath(Graph G, Vertex v, int Dist[]):計
    算圖G中頂點v到任意其他頂點的最短距離;
  • void MST(Graph G):計算圖G的最小生成樹;

怎么在程序中表示一個圖

  • 對頂點進行編號。
  • 頂點序號所對應在鄰接矩陣中的值為1。
  • 因為沒有自回路,所以對角線全為0。
  • 無向圖為對稱矩陣。

問題:對於無向圖的存儲,怎樣可以省一半空間?

  • 用一個長度為N(N+1)/2的1維數組A存儲{G00,G10,G11,……,Gn-1 0,…,Gn-1 n-1},則Gij在A中對應的下標是:(i*(i+1)/2+j)。
    -對於網絡,只要把G[i][j]的值定義為邊<vi,vj>的權重即可。

鄰接矩陣—— 有什么好處?

  • 直觀、簡單、好理解
  • 方便檢查任意一對頂點間是否存在邊
  • 方便找任一頂點的所有“鄰接點”(有邊直接相連的頂點)
  • 方便計算任一頂點的“度”(從該點發出的邊數為“出
    度”,指向該點的邊數為“入度”)
  • 無向圖:對應行(或列)非0元素的個數
  • 有向圖:對應行非0元素的個數是“出度”;對應列非0元素的
    個數是“入度”

鄰接矩陣—— 有什么不好?

  • 浪費空間—— 存稀疏圖(點很多而邊很少)有大量無效元素
  • 對稠密圖(特別是完全圖)還是很合算的
  • 浪費時間—— 統計稀疏圖中一共有多少條邊

鄰接表

  • G[N]為指針數組,對應矩陣每行一個鏈表,只存非0元素

鄰接矩陣—— 有什么好處?

  • 方便找任一頂點的所有“鄰接點”
  • 節約稀疏圖的空間:需要N個頭指針+2E(每個節點至少兩個域)
  • 方便計算任一頂點的“度”?:對無向圖:是的,對又想吐只能計算出度,需要構造“逆鄰接表”計算入度。

鄰接矩陣—— 有什么不好?

  • 不方便檢查任意一對頂點間是否存在邊。

代碼實現

  • 設定初始參數,最大值和權值頂點數
  • 設定邊結點,用於連接頂點。
  • 設定圖結點,建立頂點數,邊數,表示關系的鄰接矩陣。
  • 設定插入函數,把邊插入到圖當中。

設定參數

  • 設定INFINITY為最大值,便於權值的比較。
#define MaxVertexNum 100    /* 最大頂點數設為100 */
#define INFINITY 65535        /* ∞設為雙字節無符號整數的最大值65535*/
typedef int Vertex;         /* 用頂點下標表示頂點,為整型 */
typedef int WeightType;        /* 邊的權值設為整型 */
typedef char DataType;        /* 頂點存儲的數據類型設為字符型 */
 

設定邊結點

  • 包括邊結點、邊結點的指針、邊連接的兩個頂點和邊的權重。
/* 邊的定義 */
typedef struct ENode *PtrToENode;
struct ENode{
    Vertex V1, V2;      /* 有向邊<V1, V2> */
    WeightType Weight;  /* 權重 */
};
typedef PtrToENode Edge;
      

設定圖結點

  • 包括圖結點、圖結點的指針、包含的頂點數、邊數、圖的鄰接矩陣、頂點存儲的數據。
/* 圖結點的定義 */
typedef struct GNode *PtrToGNode;
struct GNode{
    int Nv;  /* 頂點數 */
    int Ne;  /* 邊數   */
    WeightType G[MaxVertexNum][MaxVertexNum]; /* 鄰接矩陣 */
    DataType Data[MaxVertexNum];      /* 存頂點的數據 */
    /* 注意:很多情況下,頂點無數據,此時Data[]可以不用出現 */
};
typedef PtrToGNode MGraph; /* 以鄰接矩陣存儲的圖類型 */
 

創建一個圖

  • 創建一個圖結點並將頂點初始化,返回指針。

 
MGraph CreateGraph( int VertexNum )
{ /* 初始化一個有VertexNum個頂點但沒有邊的圖 */
    Vertex V, W;
    MGraph Graph;
     
    Graph = (MGraph)malloc(sizeof(struct GNode)); /* 建立圖 */
    Graph->Nv = VertexNum;
    Graph->Ne = 0;
    /* 初始化鄰接矩陣 */
    /* 注意:這里默認頂點編號從0開始,到(Graph->Nv - 1) */
    for (V=0; V<Graph->Nv; V++)
        for (W=0; W<Graph->Nv; W++)  
            Graph->G[V][W] = INFINITY;
             
    return Graph; 
}
   

將邊插入到頂點當中

  • 接受一個邊結點,把對應值的關系儲存。
  • 若是無向圖要儲存兩次。
     
void InsertEdge( MGraph Graph, Edge E )
{
     /* 插入邊 <V1, V2> */
     Graph->G[E->V1][E->V2] = E->Weight;    
     /* 若是無向圖,還要插入邊<V2, V1> */
     Graph->G[E->V2][E->V1] = E->Weight;
}
 

建立圖


MGraph BuildGraph()
{
    MGraph Graph;
    Edge E;
    Vertex V;
    int Nv, i;
     
    scanf("%d", &Nv);   /* 讀入頂點個數 */
    Graph = CreateGraph(Nv); /* 初始化有Nv個頂點但沒有邊的圖 */ 
     
    scanf("%d", &(Graph->Ne));   /* 讀入邊數 */
    if ( Graph->Ne != 0 ) { /* 如果有邊 */ 
        E = (Edge)malloc(sizeof(struct ENode)); /* 建立邊結點 */ 
        /* 讀入邊,格式為"起點 終點 權重",插入鄰接矩陣 */
        for (i=0; i<Graph->Ne; i++) {
            scanf("%d %d %d", &E->V1, &E->V2, &E->Weight); 
            /* 注意:如果權重不是整型,Weight的讀入格式要改 */
            InsertEdge( Graph, E );
        }
    } 
 
    /* 如果頂點有數據的話,讀入數據 */
    for (V=0; V<Graph->Nv; V++) 
        scanf(" %c", &(Graph->Data[V]));
 
    return Graph;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM