c/c++連通圖的遍歷(深度遍歷/廣度遍歷)


連通圖的遍歷(深度遍歷/廣度遍歷)

概念:圖中的所有節點都要遍歷到,並且只能遍歷一次。

  • 深度遍歷
  • 廣度遍歷

深度遍歷

概念:從一個給定的頂點開始,找到一條邊,沿着這條邊一直遍歷。

廣度遍歷

概念:從一個給定的頂點開始,找到這個頂點下的所有子頂點后,再找下一層的子頂點。

深度遍歷的實現思路

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM