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隣接行列表現
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隣接テーブルの実装
特長:
- すべての頂点の隣接頂点のいずれかを見つけることは容易
- 保存スペースのまばらなグラフ
- これは、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);
}
}
}
}