1. 程式人生 > >建立圖的三種方法(鄰接矩陣+鄰接表+十字連結串列)

建立圖的三種方法(鄰接矩陣+鄰接表+十字連結串列)

一、鄰接矩陣
採用矩陣的方式來描述圖中的連線各非連線關係,若不能連上用無窮大或者0來表示,但是如果邊很稀少,頂點很多,那麼將會有很大的浪費。同時,這個矩陣可以同時刻畫有向圖和無向圖,無向圖就是把有向圖根據對角線對稱即可。

這裡寫圖片描述

1、思想:建立一個結構體,它包含了這個圖所應該具備的頂點、邊的條數、矩陣(二維陣列的資訊),同時因為邊有三個資訊,權值,連線兩個頂點v1,v2,所以也用一個結構體表示

這裡寫圖片描述
2、用到的函式:

MGraph CreateGraph_matric(int nvNum);
void InsertEdge_matric(MGraph Graph,Edge E);
MGraph biuldGraph_matric()

3、過程
(1)從檔案中讀入nv
(2)建立一個具有nv個頂點的圖:

CreateGraph_matric(nv)

申請一個鄰接矩陣圖的空間,先把邊設定成0,再用兩個for迴圈遍歷所有可能的邊,每條邊設定成無窮大(初始化)
(3)從檔案中讀入邊的資訊,讀入邊的連線資訊(權值+兩個被邊連線的頂點),把他們的資訊賦給Edge的邊的結構體,再把這條邊插進圖中

InsertEdge_matric(Graph,E);

在插入函式中,說明:哪兩個頂點間的權值是多少,即可

Graph->G[E->v1][E->v2]=E->weight;

二、鄰接表
1、結構體

/*鄰接點的定義*/
typedef int weightType;
typedef char dataType;
struct AdjvNode{
    Vertex Adjv;//鄰接點的下標
    weightType weight;
    struct AdjvNode *next;
};
typedef struct AdjvNode *PtrToAdjvNode;


/*頂點表頭結點的定義*/
struct Vnode{
    PtrToAdjvNode firstEdge;//邊表頭指標
    dataType data;
};
//開闢頂點結點的陣列
typedef struct
Vnode AdjList[MaxVertexNum]; /*鄰接表-圖的定義*/ struct GNode_AL{ int nv; int ne; AdjList G;//頂點表 }; typedef struct GNode_AL *LGraph;

這裡寫圖片描述

鄰接表的結構是這樣構建的:
整個圖應該由頂點表+邊表構成,怎麼把他們連線起來?
(大框架)(裡邊包含頂點表,邊數,頂點數)->(頂點表)(又包含 頂點內容+指向邊表的指標)->(指標引出邊表)(邊表包含 :被指向邊的頂點+權值+指向該條連結串列的下一個指標)

這裡寫圖片描述
2、用到函式
同鄰接矩陣(3個)
3、建立過程
同鄰接矩陣。
初始化的時候有些區別。剛開始的時候,除了申請一個圖的空間,還給每個頂點表也申請了空間,其實根本不用,因為我們建立的頂點表是用陣列來建立的,已經申請了空間。把每個頂點表的頭指標賦值為NULL。

//建立鄰接表的圖
LGraph biuldGraph_adjacencyList(){
    LGraph Graph;
    Edge E;
    int nv,i;

    FILE*fp;
     if((fp=fopen("E://資料結構//圖 實驗//matric1.txt","r"))==NULL)
    {
        printf("fail to open!");
        exit(0);
    }
    fscanf(fp,"%d\n",&nv);//頂點個數
    Graph=CreateGraph_adjacencyList(nv);//初始化有nv個頂點但沒有邊的圖

    fscanf(fp,"%d\n",&Graph->ne);//讀入邊數
    if(Graph->ne!=0){
        E=(Edge)malloc(sizeof(struct ENode));
        for(i=0;i<Graph->ne;i++){
            fscanf(fp,"%d %d %d\n",&E->v1,&E->v2,&E->weight);//讀入邊的資訊
            InsertEdge_adjacencyList(Graph,E);//把這條邊插入矩陣資訊中
        }
    }
    //讀入頂點的資料
    for(i=0;i<Graph->nv;i++){
        fscanf(fp,"%c",&Graph->G[i].data);//讀入A、B、C頂點的資料
    }
    return Graph;
}
//初始化有nv個頂點但沒有邊的圖
LGraph CreateGraph_adjacencyList(int nvNum){
    Vertex v;
    LGraph Graph;
    //為這個圖申請空間
    Graph =(LGraph)malloc(sizeof(struct GNode));
    Graph->nv=nvNum;
    Graph->ne=0;
    for(v=0;v<Graph->nv;v++)
        Graph->G[v].firstEdge=NULL;
    return Graph;
}

插入的時候,每一行的插入都是往前插

//把這條邊插入鄰接表資訊中
void InsertEdge_adjacencyList(LGraph Graph,Edge E){
    PtrToAdjvNode newnode;//定義一個表頭結點
    //建立一個v2鄰接點
    newnode=(PtrToAdjvNode)malloc(sizeof(struct AdjvNode));
    newnode->Adjv=E->v2;//被連線到的點
    newnode->weight=E->weight;
    //將v2插入v1表頭
    newnode->next=Graph->G[E->v1].firstEdge;
    Graph->G[E->v1].firstEdge=newnode;
}

如何理解將v2插入v1表頭
這裡寫圖片描述

三、十字連結串列
1、結構體

/*十字連結串列的結構體*/
//結點結構
struct ArcNode{
    int tailvex,headvex;//弧的頭和頂點的位置
    struct ArcNode *hlink,*tlink;//頭尾指標
    weightType weight;
};
typedef struct ArcNode *Arcbox;

//頭結點
struct XNode{
    dataType data;
    Arcbox firstIn,firstOut;
};
typedef struct XNode xlist[MaxVertexNum];

/*十字連結串列-圖的定義*/
struct OLGNode{
    int nv;
    int ne;
    xlist G;//鄰接表
};
typedef struct OLGNode *OLGraph;

結點表和邊表都多了一個方向的指標

這裡寫圖片描述

2、過程
這個一模一樣,不寫了

OLGraph biuldGraph_arc(){}

下面這個for語句是要對兩個頭尾指標都要賦初值NULL,但是沒有用括號,導致另一個指標瞎指,找了好久才發現,一定要細心!!

//初始化有nv個頂點但沒有邊的圖
OLGraph CreateGraph_arc(int nvNum){
    Vertex v;
    OLGraph Graph;
    //為這個圖申請空間
    Graph =(OLGraph)malloc(sizeof(struct OLGNode));
    Graph->nv=nvNum;
    Graph->ne=0;
    /*
    for(v=0;v<Graph->nv;v++)
        Graph->G[v].firstIn=NULL;
        Graph->G[v].firstOut=NULL;出錯原因!!

    */
    for(v=0;v<Graph->nv;v++){
        Graph->G[v].firstIn=NULL;
        Graph->G[v].firstOut=NULL;
    }
    return Graph;
}
//把這條邊插入鄰接表資訊中
void InsertEdge_arc(OLGraph Graph,Edge E){
    Arcbox A;
    A=(Arcbox)malloc(sizeof(struct ArcNode));//為結點申請空間

    A->weight=E->weight;
    A->headvex=E->v2;
    A->tailvex=E->v1;

    A->tlink=Graph->G[A->tailvex].firstOut;//出去的指標解決了
    Graph->G[A->tailvex].firstOut=A;//把出去的邊連線上
    //解決firstIn,hlink的指標
    A->hlink=Graph->G[A->headvex].firstIn;
    Graph->G[A->headvex].firstIn=A;
}

firstout-tlink firstin-hlink