圖的結構與操作
阿新 • • 發佈:2019-01-26
圖的結構
1、鄰接矩陣結構
#define MAXSIZE 100
#define INFINITY 65535 //無窮大,表示兩點直接沒有路徑連線
typedef struct Mgraph{
char vex[MAXSIZE]; //定義頂點陣列
int arc[MAXSIZE][MAXSIZE]; //定義鄰接矩陣
int numvex, numedge; //定義頂點個數和邊的個數
};
無向矩陣的建立void CreatMgraph(Mgraph *G){ int i, j, k, weight; //weight表示邊上的權值 scanf("%d,%d", &G->numvex, &G->numedge); //讀入頂點個數和邊個數 for (i = 0; i < numvex; i++) scanf("%c", &G->vex[i]); //讀入頂點資訊到陣列中 for (i = 0; i < numvex; i++) for (j = 0; j < numvex; j++) G->arc[i][j] = INFINITY; //初始化鄰接矩陣陣列為無窮大 for (k = 0; k < numedge; k++){ scanf("%d,%d,%d", &i, &j, &weight); //讀入邊之間的路徑(vi,vj)和權值 G->arc[i][j] = weight; G->arc[j][i] = weight; //此處為無向圖,因此矩陣的權值是對角對稱結構。如果為有向圖,則需要另考慮權值 } }
2、鄰接表的結構
typedef struct EdgeNode{
int adjvex; //鄰接點對應的下標
int weight; //權值
struct EdgeNode *next;
};
typedef struct VexNode{ //頂點結點
int data; //頂點資訊
struct EdgeNode *first; //頭指標
};
typedef struct Graphlist{ //鄰接表結構
VexNode adjlist[MAXSIZE];
int numvex, numedge; //頂點數和邊數
};
無向圖鄰接表的建立
還有十字連結串列、鄰接多重連結串列、邊集陣列結構void CreatGraphlist(Graphlist *G){ int i, j, k,w; scanf("%d,%d", &G->numvex, &G->numedge); //讀入邊和頂點的個數 for (i = 0; i < numvex; i++){ scanf("%c", &G->adjlist[i].data); //讀入頂點資訊 G->adjlist[i].first = nullptr; //初始化頭指標 } for (k = 0; k < numedge; k++){ scanf("%d,%d,%d", &i, &j, &w); //讀入邊(vi,vj)以及對應的權值 EdgeNode *e = (EdgeNode *)malloc(sizeof(EdgeNode)); e->adjvex = j; e->weight = w; e->next = G->adjlist[i].first; G->adjlist[i].first = e; //此處用的是連結串列操作的頭插法 } }
關於圖的遍歷,主要為兩種,深度優先遍歷DFS和廣度優先遍歷BFS
廣度優先遍歷DFS--類似於樹的前序遍歷操作,
鄰接矩陣的深度優先遍歷
bool visited[MAX]; //使用一個標誌陣列來儲存訪問的資訊 void DFS(MGraph G, int i){ //從第i個頂點開始遍歷的DFS遞迴演算法 int j; visited[i] = true; //true表示該頂點被訪問過 printf("%c", G.vex[i]); for (j = 0; j <G.numvex; j++) if (G.arc[i][j] != INFINITY &&!visited[j]) DFS(G, j); } void DFSTraverse(MGraph G){ //DFS遍歷操作 int i; for (i = 0; i <G.numvex; i++) visited[i] = false; //初始化標誌陣列,表示所有頂點都未訪問過 for (i = 0; i < G.numvex; i++) if (!visited[i]) // 連通圖的話,只執行一次,非連通圖會至少兩次 DFS(G, i); }
鄰接表的深度優先遍歷
void DFS(Graphlist *G, int i){ //從第i個頂點開始遍歷的DFS遞迴演算法
EdgeNode *p; //相當於鄰接矩陣中的j
visited[i] = true;
printf("%c", G->adjlist[i].data);
p = G->adjlist[i].first; //相當於j=0
while (p){
if (!visited[i])
DFS(G, p->adjvex);
p = p->next; //相當於j++
}
}
void DFSTraverse(Graphlist *G){ //DFS遍歷操作
int i;
for (i = 0; i < G->numvex; i++)
visited[i] = false;
for (i = 0; i < G->numvex; i++)
if (!visited[i]) // 連通圖的話,只執行一次,非連通圖會至少兩次
DFS(G, i);
}
廣度優先遍歷BFS --類似於樹的層遍歷方式,需要藉助一個佇列輔助來實現
佇列Queue的操作在前面總結當中提過,不再重新定義,不過要注意,根據實際情況,隊列當中的資料型別可能會是圖 sturct MGraph型別或者struct Graphlist型別
鄰接矩陣的廣度遍歷BFS
void BFSTraverse(MGraph G){
int i, j;
Queue Q; //輔助佇列
for (i = 0; i < G.numvex; i++)
visited[i] = false;
InitQueue(&Q); //初始化佇列
for (i = 0; i < G.numvex; i++){
if (!visited[i]){
visited[i] = true; // 連通圖的話,只執行一次,非連通圖會至少兩次
printf("%c", G.vex[i]);
EnQueue(&Q, &i); //從第i個頂點開始BFS遍歷
while (!QueueEmpty(Q)){ //佇列不為空的時候繼續遍歷
Dequeue(&Q, &i);
for (j = 0; j < G.numvex; j++){
if (G.arc[i][j] != INFINITY && !visited){ //判斷該頂點與其他頂點是否相連,並列印相連的頂點
visited[j] = true;
printf("%c", G.vex[j]);
Enqueue(&Q, &i); //將相鄰的頂點存入佇列中
}
}
}
}
}
}
鄰接表的BFS
void BFSTraverse(Graphlist *G){
EdgeNode *p; //相當於鄰接表中的j
int i;
Queue Q;
for (i = 0; i < G->numvex; i++)
visited[i] = false;
InitQueue(&Q);
for (i = 0; i < G->numvex; i++){
if (!visited[i]){
visited[i] = true; // 連通圖的話,只執行一次,非連通圖會至少兩次
printf("%c", G->adjlist[i].data);
EnQueue(&Q, &i);
while (!QueueEmpty(Q)){ //佇列不為空的時候繼續遍歷
DeQueue(&Q, &i);
p = G->adjlist[i].first; //相當於j=0
while (p){
if (!visited[p->adjvex]){
visited[p->adjvex] = true;
printf("%c", G->adjlist[p->adjvex].data);
Enqueue(&Q, &i);
}
p = p->next; //相當於j++
}
}
}
}
}