連通圖的遍歷(深度遍歷/廣度遍歷)
概念:圖中的所有節點都要遍歷到,並且只能遍歷一次。
- 深度遍歷
- 廣度遍歷
深度遍歷
概念:從一個給定的頂點開始,找到一條邊,沿着這條邊一直遍歷。
廣度遍歷
概念:從一個給定的頂點開始,找到這個頂點下的所有子頂點后,再找下一層的子頂點。
深度遍歷的實現思路
1,創建一個bool數組,用來識別哪個頂點已經被遍歷過了。
2,遞歸
3,遞歸找給定頂點是否有下一個頂點(方法:get_first_neighbor),都找完后,
4,再遞歸找給定頂點之后的在3處找到的頂點后的下一個頂點(方法:get_next_neighbor)
光度遍歷的實現思路
1,用隊列實現,先入隊給定頂點
2,出隊
3,入隊:與在2處出隊的頂點有相連的頂點
代碼
graph_link.h
#ifndef __graph_link__
#define __graph_link__
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <memory.h>
#include <stdbool.h>
#define default_vertex_size 10
#define T char
//邊的結構
typedef struct Edge{
//頂點的下標
int idx;
//指向下一個邊的指針
struct Edge* link;
}Edge;
//頂點的結構
typedef struct Vertex{
//頂點的值
T data;
//邊
Edge* adj;
}Vertex;
//圖的結構
typedef struct GraphLink{
int MaxVertices;
int NumVertices;
int NumEdges;
Vertex* nodeTable;
}GraphLink;
//初始化圖
void init_graph_link(GraphLink* g);
//顯示圖
void show_graph_link(GraphLink* g);
//插入頂點
void insert_vertex(GraphLink* g, T v);
//插入邊尾插
void insert_edge_tail(GraphLink* g, T v1, T v2);
//插入邊頭插
void insert_edge_head(GraphLink* g, T v1, T v2);
//刪除邊
void remove_edge(GraphLink* g, T v1, T v2);
//刪除頂點
void remove_vertex(GraphLink* g, T v);
//銷毀圖
void destroy_graph_link(GraphLink* g);
//取得指定頂點的第一個后序頂點
int get_first_neighbor(GraphLink* g, T v);
//取得指定頂點v1的臨街頂點v2的第一個后序頂點
int get_next_neighbor(GraphLink* g, T v1, T v2);
//深度遍歷
void dfs_graph(GraphLink* g, T v);
//取得頂點的data值
T getVertexValue(GraphLink* g, int i);
//廣度遍歷
void cfs_graph(GraphLink* g, T v);
#endif
graph_link.c
#include "graph_link.h"
#include "nodequeue.h"
//初始化圖
void init_graph_link(GraphLink* g){
g->MaxVertices = default_vertex_size;
g->NumVertices = g->NumEdges = 0;
g->nodeTable = (Vertex*)malloc(sizeof(Vertex) * g->MaxVertices);
assert(NULL != g->nodeTable);
for(int i = 0; i < g->MaxVertices; ++i){
g->nodeTable[i].adj = NULL;
}
}
//顯示圖
void show_graph_link(GraphLink* g){
if(NULL == g)return;
for(int i = 0; i < g->NumVertices; ++i){
printf("%d %c->", i, g->nodeTable[i].data);
Edge* p = g->nodeTable[i].adj;
while(NULL != p){
printf("%d->", p->idx);
p = p->link;
}
printf(" NULL\n");
}
}
//插入頂點
void insert_vertex(GraphLink* g, T v){
if(g->NumVertices >= g->MaxVertices)return;
g->nodeTable[g->NumVertices++].data = v;
}
//查找頂點的index
int getVertexIndex(GraphLink* g, T v){
for(int i = 0; i < g->NumVertices; ++i){
if(v == g->nodeTable[i].data)return i;
}
return -1;
}
//插入邊(頭插)
void insert_edge_head(GraphLink* g, T v1, T v2){
int p1 = getVertexIndex(g, v1);
int p2 = getVertexIndex(g, v2);
if(p1 == -1 || p2 == -1)return;
Edge* p = (Edge*)malloc(sizeof(Edge));
p->idx = p2;
p->link = g->nodeTable[p1].adj;
g->nodeTable[p1].adj = p;
p = (Edge*)malloc(sizeof(Edge));
p->idx = p1;
p->link = g->nodeTable[p2].adj;
g->nodeTable[p2].adj = p;
}
//取得指定頂點的第一個后序頂點
int get_first_neighbor(GraphLink* g, T v){
int i = getVertexIndex(g, v);
if (-1 == i)return -1;
Edge* p = g->nodeTable[i].adj;
if(NULL != p)
return p->idx;
else
return -1;
}
//取得指定頂點v1的臨街頂點v2的第一個后序頂點
int get_next_neighbor(GraphLink* g, T ve1, T ve2){
int v1 = getVertexIndex(g, ve1);
int v2 = getVertexIndex(g, ve2);
if(v1 == -1 || v2 == -1)return -1;
Edge* t = g->nodeTable[v1].adj;
while(t != NULL && t->idx != v2){
t = t->link;
}
if(NULL != t && t->link != NULL){
return t->link->idx;
}
return -1;
}
//取得頂點的data值
T getVertexValue(GraphLink* g, int i){
if(i == -1)return 0;
return g->nodeTable[i].data;
}
//深度遍歷
void dfs_graph_v(GraphLink* g, int v, bool* visited){
printf("%c->", getVertexValue(g,v));
visited[v] = true;
//取得相鄰頂點的下標
int w = get_first_neighbor(g, getVertexValue(g, v));
while(w != -1){
if(!visited[w]){
dfs_graph_v(g, w, visited);
}
w = get_next_neighbor(g, getVertexValue(g, v), getVertexValue(g,w));
}
}
void dfs_graph(GraphLink* g, T v){
int cnt = g->NumVertices;
bool* visited = (bool*)malloc(sizeof(bool) * cnt);
assert(NULL != visited);
for(int i = 0; i < cnt; ++i){
visited[i] = false;
}
int index = getVertexIndex(g, v);
dfs_graph_v(g, index, visited);
free(visited);
}
//廣度遍歷
void cfs_graph(GraphLink* g, T v){
//創建一個輔助的bool數組,用來識別哪個頂點已經被遍歷過了
int cnt = g->NumVertices;
bool* visited = (bool*)malloc(sizeof(bool) * cnt);
assert(NULL != visited);
for(int i = 0; i < cnt; ++i){
visited[i] = false;
}
//創建隊列
NodeQueue q;
init(&q);
//入隊
int tar = getVertexIndex(g, v);
enQueue(&q, tar);
//隊列不為空就執行
while(length(&q) != 0){
//取得隊列的第一個元素
int ve = getHead(&q)->data;
printf("%c->", getVertexValue(g, ve));
visited[ve] = true;
//出隊
deQueue(&q);
Edge* e = g->nodeTable[ve].adj;
while(NULL != e){
//如果這個頂點沒有被遍歷過,入隊
if(!visited[e->idx]){
visited[e->idx] = true;
enQueue(&q, e->idx);
}
e = e->link;
}
}
}
graph_linkmain.c
#include "graph_link.h"
int main(){
GraphLink gl;
//初始化圖
init_graph_link(&gl);
//插入節點
insert_vertex(&gl, 'A');
insert_vertex(&gl, 'B');
insert_vertex(&gl, 'C');
insert_vertex(&gl, 'D');
insert_vertex(&gl, 'E');
insert_vertex(&gl, 'F');
insert_vertex(&gl, 'G');
insert_vertex(&gl, 'H');
insert_edge_head(&gl, 'A', 'B');
insert_edge_head(&gl, 'A', 'C');
insert_edge_head(&gl, 'B', 'D');
insert_edge_head(&gl, 'B', 'E');
insert_edge_head(&gl, 'C', 'F');
insert_edge_head(&gl, 'C', 'G');
insert_edge_head(&gl, 'D', 'H');
insert_edge_head(&gl, 'E', 'H');
insert_edge_head(&gl, 'F', 'G');
//顯示圖
show_graph_link(&gl);
//深度遍歷
dfs_graph(&gl, 'E');
printf("null\n");
//廣度遍歷
cfs_graph(&gl, 'F');
printf("null\n");
}
完整代碼
編譯方法:g++ -g nodequeue.c graph_link.c graph_linkmain.c