數據結構與算法 -- 圖(鄰接矩陣)原理詳解

PS:圖在數據結構中有着很是大的份量,它比樹有着更爲複雜的形式結構,這裏就再也不說圖的基本概念,直接就說圖的存儲結構,鄰接矩陣和鄰接表。圖是有方向的,有方向的叫作弧,無方向的叫作邊。存儲圖中各頂點自己數據,使用一維數組就足夠了;存儲頂點之間的關係時,要記錄每一個頂點和其它全部頂點之間的關係,因此須要使用二維數組。圖在大多行業中的使用也是不少的,好比說遊戲中兩我的物的尋址,自動尋路,就是圖與圖直接通過計算而後移動。後序還會介紹Dijkstra(迪傑斯特拉)算法計算最短路徑問題。linux

下面介紹鄰接矩陣原理:算法

下面能夠看到頂點之間有必定的聯繫,若是想要把他們存放在計算機中怎麼存入呢,首先咱們想到的是把頂點存在一維數組中,那麼他們的關係存在在二維數組中,就好像是以下格式,A->B 權值是10,B->E 權值30。(下方1爲有關係,0爲沒有關係,未加入權值)數組

思路

首先把要知道頂點和邊數,而後單獨把頂點存在一維數組中,根據邊來肯定兩個頂點之間的聯繫,好比說第一條邊,是A->B。歸根結底也是經過數組來存儲。固然這是鄰接矩陣。數據結構

步驟

  1. 定義結構體
  2. 輸入頂點和邊數
  3. 經過頂點和邊數初始化數據(內部全是0或者是無窮)
  4. 打印表
  5. 遍歷(深度和廣度優先遍歷)

1:結構體定義

typedef char VertexType;
typedef int EdgeType;
#define MAXVEX 100
#define IUNFINITY 65535

typedef struct {
    VertexType vexs[MAXVEX];        /* 頂點表*/
    EdgeType arc[MAXVEX][MAXVEX];   /* 鄰接矩陣 */
    int vnum, edgenum;               /*定點的個數和邊的個數*/
} MGraphy;

2:數據初始化

代碼中有不少註釋,有沒有用到的,可是一種經驗。 函數

//加入權值
void createGraphyWeight(MGraphy *g) {
    printf("輸入總頂點(空格)邊數\n");
    scanf("%d %d", &g->vnum, &g->edgenum);
    printf("輸入 頂點表示:\n");
    //頂點請輸入;
    for (int i = 0; i < g->vnum; i++) {
        printf("請輸入第%d個頂點", (i + 1));
//        fflush(stdin);//不起做用,資料顯示一些linux平臺下一些庫沒有定義這個方法。
//        flushall(); //清除多餘的回車符。
        //若是不加入getchar的話,在for循環中就會先執行一遍scanf,由於上面可能會有一些回車,致使執行一遍scanf。須要清除以前的回車。
        getchar();
        scanf("%c", &g->vexs[i]);
    }
    for (int i = 0; i < g->vnum; i++) {                               // 初始化數組元素 Infonity
        for (int j = 0; j < g->vnum; j++) {
//            g->arc[i][j] = IUNFINITY;//對於加權值的默認所有設置爲最大值,
            g->arc[i][j] = 0;//對於未加權值的默認所有設置爲0
        }
    }
    printf("輸入邊有關的兩個頂點,\n");
    for (int i = 0; i < g->edgenum; i++) {
        char a, b;
        int c ;
        printf("輸入第 %d 條邊有關的兩個頂點加權值(空格隔開),沒有權值輸入0\n ", (i + 1));
        getchar();
//        setbuf(stdin,NULL);
        scanf("%c %c %d", &a, &b,&c);
        int ii = localGV(g, a);
        int jj = localGV(g, b);
        if(c == 0){
            c=1;
        }
//        printf("c的值是%d",c);
        g->arc[ii][jj] = c;
        g->arc[jj][ii] = c;    // 無向圖
    }
    printfL(g);


}

 3:打印表

void printfL(MGraphy *g) {
    //輸出圖的信息
    printf("表爲 :\n");
    int i = 0;
    //先打印行標題;頂點標題
    for (i = 0; i < g->vnum + 1; i++) {
        if (i > 0) {
            printf("%c\t", g->vexs[i - 1]);
        } else {
            printf("\\\t");
        }
    }
    printf("\n");
    for (i = 0; i < g->vnum; i++) {
        printf("%c\t", g->vexs[i]);
        for (int j = 0; j < g->vnum; j++) {
            printf("%d\t", g->arc[i][j]);
        }
        printf("\n");
    }
}

 4:深度優先遍歷

這裏的深度優先遍歷只給出代碼,原理後序會給出。調試

//深度優先搜索
void DFSTraverse(MGraphy *G){//
    int v;
    //將用作標記的visit數組初始化爲false
    for( v = 0; v < G->vnum; ++v){
        visited[v] = false;
    }
    //對於每一個標記爲false的頂點調用深度優先搜索函數
    for( v = 0; v < G->vnum; v++){
        //若是該頂點的標記位爲false,則調用深度優先搜索函數
        if(!visited[v]){
            DFS(G, v);
        }
    }
}
int FirstAdjVex(MGraphy *g,int v)
{
    //查找與數組下標爲v的頂點之間有邊的頂點,返回它在數組中的下標
    for(int i = 0; i<g->vnum; i++){
        if( g->arc[v][i]){
            return i;
        }
    }
    return -1;
}
int NextAdjVex(MGraphy *G,int v,int w)
{
    //從前一個訪問位置w的下一個位置開始,查找之間有邊的頂點
    for(int i = w+1; i<G->vnum; i++){
        //最關鍵的一個判斷,調試了好久,讓其等於'1'或者 !=0 ,不然該字符不知道後面仍是否有值相鏈接。
        if(G->arc[v][i] != 0){
            return i;
        }
    }
    return -1;
}
void DFS(MGraphy *g,int v){
    visited[v]= true;
    printf("%c",g->vexs[v]);//輸入data值
    //從該頂點的第一個邊開始,一直到最後一個邊,對處於邊另外一端的頂點調用DFS函數
    int w;
    for( w= FirstAdjVex(g,v); w>=0; w = NextAdjVex(g,v,w)){
        //若是該頂點的標記位false,證實未被訪問,調用深度優先搜索函數
        if(!visited[w]){
            DFS(g,w);
        }
    }
}

blog

相關文章
相關標籤/搜索