ALGO&DS [5]。図そのストレージ構造トラバーサル

1.マップとは何ですか

の「多くの多」の関係を示す
含む
頂点の集合を:通常V(頂点)頂点の集合表す
エッジの集合を:通常E(エッジが示されている)セット側の
エッジの頂点は、(V、W)∈E 、ここで、V、∈V、V W W
有向枝<V、W W>→V(単一線)Vから有向エッジ表しwが
考慮されていないが、回路側重量から

一般的な用語は、
グラフ無向:問題ではない全てのエッジの方向に図の
有向グラフ:グラフのエッジは、双方向性であってもよいが、一方向であってもよい、方向は非常に重要である
重量:各エッジに割り当てられた値のための図、実用的な意義の様々なあってもよい
ネットワーク:図加重値
隣接点:直接接続YESエッジ頂点
度:頂点から発するエッジ数
浸透:エッジの数を指す頂点
スパースグラフ:多くの頂点と図エッジ少し
図稠密:あまりにも多くの頂点多角図
完全グラフ:頂点の集合に対して与えられたとの間に、頂点エッジが存在します

抽象データ型定義
タイプ名:図(グラフ)。
データオブジェクトのセット:G(V、E)は、頂点VとからなるエッジEの有限集合の空でない有限集合から成る
一連の操作:任意のグラフG∈グラフ、及びv∈ためV、E∈E
の主な操作は次のとおりです。

グラフクレートは():作成して戻る図空
グラフInsertVertex(グラフG、頂点v ): VインサートG
グラフInsertEdge(グラフG、エッジe):EはGが挿入されている
頂点から:DFS(グラフG、頂点V)を無効図深さ優先探索開始V Gは、
幅最初のトラバーサルは、図1の頂点V Gから出発:BFS(グラフG、頂点V)を無効。

2.図に示すストレージ構造

2.1隣接行列表現

Snipaste_2019-11-23_11-43-39.png

Gの隣接行列[N] [N] - 0からN-1個のN頂点

縁あり<vi,vj>、G [I] [J] = 1、 そうでなければ0が

ここで
対角要素はすべて0で
斜めの線対称に

利点
直感的な、シンプルで理解しやすい
エッジが検査を容易にするために、頂点の任意の対の間に存在するかどうかを
すべてのネイバーのいずれかの頂点を見つけることは容易で
計算の便宜の各頂点の
無向グラフを非ゼロ要素の対応する行(または列)番号
有向グラフ:非対応する行が0の要素数であり、要素の数に対応する列は、非ゼロ度であります

欠点
スペースの廃棄物-スパースグラフ保持
縁統計スパースグラフ-時間の無駄

コードの実装

#include<stdio.h>
#include<stdlib.h>
#define MaxVertexNum 100
typedef int weightType;
typedef int Vertex;
typedef int DataType;
typedef struct GNode *ptrToGNode;
struct GNode{   // 图 
    int Nv;   // 顶点数 
    int Ne;   // 边数
    weightType G[MaxVertexNum][MaxVertexNum];
    DataType Data[MaxVertexNum]; // 存顶点的数据 
}; 
typedef ptrToGNode MGraph;
typedef struct ENode *ptrToENode;
struct ENode{  // 边 
    Vertex V1,V2;    // 有向边<V1,V2> 
    weightType Weight;  // 权重 
};
typedef ptrToENode Edge;

// 初始化图 
MGraph Create(int VertexNum){
    Vertex v,w;
    MGraph Graph;
    
    Graph = (MGraph)malloc(sizeof(struct GNode));
    Graph->Nv = VertexNum;
    Graph->Ne = 0;
    
    for(v=0;v<VertexNum;v++)
        for(w=0;w<VertexNum;w++)
            Graph->G[v][w] = 0;
    return Graph;
}

// 插入边 
MGraph Insert(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 = Create(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);  // 读入每个边的数据 
            Insert(Graph,E);
        }
    }
    return Graph;
}

// 遍历图
void print(MGraph Graph){
    Vertex v,w;
    for(v=0;v<Graph->Nv;v++){
        for(w=0;w<Graph->Nv;w++)
            printf("%d ",Graph->G[v][w]);
        printf("\n");
    }
} 

int main(){
    MGraph Graph;
    Graph = BuildGraph();
    print(Graph);
    return 0;
}

2.2隣接テーブルの実装

Snipaste_2019-11-23_11-42-25.png

特長:

  • すべての頂点の隣接頂点のいずれかを見つけることは容易
  • 保存スペースのまばらなグラフ
    • これは、N + 2Eヘッド・ポインタ・ノード(少なくとも二つのドメインの各ノード)が必要
  • 頂点のいずれかどうか計算の便宜のために
    • 無向グラフ:簡単
    • 有向グラフ:計算度だけ
  • 頂点間のエッジが存在するか否かを任意のペア便利チェック

コードの実装

#include<stdio.h>
#include<stdlib.h>
#define MaxVertexNum 100
typedef int Vertex; 
typedef int DataType; 
typedef int weightType;  

typedef struct ENode *ptrToENode;
struct ENode{  // 边 
    Vertex V1,V2;    // 有向边<V1,V2> 
    weightType Weight;  // 权重 
};
typedef ptrToENode Edge;

typedef struct AdjVNode *ptrToAdjVNode;
struct AdjVNode{  // 邻接表内元素 
    Vertex AdjV;  // 邻接点下标 
    weightType Weight;  // 权值 
    ptrToAdjVNode Next;  // 下一个 
};

typedef struct VNode{  // 邻接表头 
    ptrToAdjVNode FirstEdge;  // 存每个顶点指针
    DataType Data;  // 顶点数据 
}AdjList[MaxVertexNum];

typedef struct GNode *ptrToGNode;
struct GNode{  // 图 
    int Nv;  // 顶点
    int Ne;  // 边数 
    AdjList G; // 邻接表 
}; 
typedef ptrToGNode LGraph;

// 初始化 
LGraph create(int VertexNum){
    Vertex v,w;
    LGraph Graph;
    
    Graph = (LGraph)malloc(sizeof(struct GNode));
    Graph->Nv = VertexNum;  // 初始化边
    Graph->Ne = 0;   // 初始化点
    
    // 每条边的 FirstEdge 指向 NULL 
    for(v=0;v<Graph->Nv;v++)
        Graph->G[v].FirstEdge = NULL;
    return Graph;
}

// 插入一条边到邻接表的顶点指针之后 
void InsertEdge(LGraph Graph,Edge E){
    ptrToAdjVNode newNode; 
    
    /**************** 插入边<V1,V2> ******************/ 
    // 为 V2 建立新的结点 
    newNode = (ptrToAdjVNode)malloc(sizeof(struct AdjVNode));
    newNode->AdjV = E->V2;
    newNode->Weight = E->Weight;
    
    // 将 V2 插入到邻接表头 
    newNode->Next = Graph->G[E->V1].FirstEdge;
    Graph->G[E->V1].FirstEdge = newNode;
    
    /*************** 若为无向图,插入边<V2,V1> *************/ 
    newNode = (ptrToAdjVNode)malloc(sizeof(struct AdjVNode));
    newNode->AdjV = E->V1;
    newNode->Weight = E->Weight;
    
    newNode->Next = Graph->G[E->V2].FirstEdge;
    Graph->G[E->V2].FirstEdge = newNode;
} 

// 建图
LGraph BuildGraph(){
    LGraph Graph;
    Edge E;
    Vertex V;
    int Nv,i;
    scanf("%d",&Nv);
    Graph = create(Nv);
    scanf("%d",&(Graph->Ne));
    if(Graph->Ne != 0){
        for(i=0;i<Graph->Ne;i++){
            E = (Edge)malloc(sizeof(struct ENode));
            scanf("%d %d %d",&E->V1,&E->V2,&E->Weight);
            InsertEdge(Graph,E);
        }
    }
    return Graph;
} 

// 打印 
void print(LGraph Graph){
    Vertex v;
    ptrToAdjVNode tmp;
    for(v=0;v<Graph->Nv;v++){
        tmp = Graph->G[v].FirstEdge;
        printf("%d ",v);
        while(tmp){
            printf("%d ",tmp->AdjV);
            tmp = tmp->Next;
        }
        printf("\n");
    }
}

int main(){
    LGraph Graph;
    Graph = BuildGraph();
    print(Graph);
    return 0;
}

3.グラフトラバーサル

3.1深さ優先探索DFS

void DFS ( Vertex V ){
    visited[ V ] = true;
    for ( V 的每个邻接点 W )
        if( !visited[ W ])
            DFS( W );
}

3.2 BFS BFS

void BFS( Vertex V ){
    queue<Vertex> q;
    visited[V] = true;
    q.push(V);
    while(!q.empty()){
        V = q.front(); q.pop();
        for( V 的每个邻接点 W ){
            if( !visited[ W ]){
                visited[W] = true;
                q.push(W);
            }
        }
    }
}

おすすめ

転載: www.cnblogs.com/ericling/p/11917034.html