c/c++ 圖的創建及圖的相關函數(鏈表法)


c/c++ 圖的創建及圖的相關函數(鏈表法)

圖的概念

  • 圖由點和線組成
  • 知道了圖中有多少個點,和哪些點之間有線,就可以把一張圖描繪出來
  • 點之間的線,分有方向和無方向

創建圖

創建圖,實際就是創建出節點,和節點之間的線。

下面的代碼實現了上面的圖的創建

graph_link.h

#ifndef __graph_link__
#define __graph_link__

#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <memory.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);

#endif

graph_link.c

#include "graph_link.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 buyEdge(Edge** e, int idx){
  Edge* p = (Edge*)malloc(sizeof(Edge));
  p->idx = idx;
  p->link = NULL;
  if(NULL == *e){
    *e = p;
  }
  else{
    Edge* tmp = *e;
    while(tmp->link != NULL){
      tmp = tmp->link;
    }
    tmp->link = p;
  }
}
//插入邊(尾插)
void insert_edge_tail(GraphLink* g, T v1, T v2){
  int p1 = getVertexIndex(g, v1);
  int p2 = getVertexIndex(g, v2);

  if(p1 == -1 || p2 == -1)return;
  
  buyEdge(&(g->nodeTable[p1].adj), p2);
  g->NumEdges++;
  buyEdge(&(g->nodeTable[p2].adj), p1);
  g->NumEdges++;

}
//插入邊(頭插)
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 remove_edge_(Edge** p, int i){
  if(NULL == *p)return -1;
  Edge* f;
  //判斷第一個邊是否是目標邊
  if((*p)->idx == i){
    //刪除第一條邊
    f = *p;
    *p = (*p)->link;
    free(f);
    return 0;
  }

  Edge* tmp = *p;
  while(tmp->link != NULL && tmp->link->idx != i){
    tmp = tmp->link;
  }
  //沒有找到邊
  if(tmp->link == NULL){
    return -1;
  }
  //找到邊
  else{
    f = tmp->link;
    tmp->link = tmp->link->link;
    free(f);
    return 0;
  }

}
void remove_edge(GraphLink* g, T v1, T v2){
  int p1 = getVertexIndex(g, v1);
  int p2 = getVertexIndex(g, v2);

  if(p1 == -1 || p2 == -1)return;

  int r = remove_edge_(&(g->nodeTable[p1].adj), p2);
  if(r == 0){
    g->NumEdges--;
    remove_edge_(&(g->nodeTable[p2].adj), p1);
    g->NumEdges--;
  }

}
//刪除頂點
void remove_vertex(GraphLink* g, T v){
  int p = getVertexIndex(g, v);

  if(p == -1)return;

  //刪除目標頂點以外的頂點,與目標頂點之間的邊
  for(int i = 0; i < g->NumVertices; ++i){
    if(i == p){
      continue;
    }else{
      remove_edge_(&(g->nodeTable[i].adj), p);
    }
  }

  //刪除目標頂點行的所有邊
  Edge* te = g->nodeTable[p].adj;
  Edge* tmp;
  while(te != NULL){
    tmp = te;
    te = te->link;
    free(tmp);
  }

  //讓被刪除頂點那行,指向最后一個頂點那行。
  //因為最后一行向上移動了,所以要修改和最后一行有連線的點那行的線的下標。
  g->nodeTable[p].data = g->nodeTable[g->NumVertices - 1].data;
  g->nodeTable[p].adj = g->nodeTable[g->NumVertices - 1].adj;
  tmp = g->nodeTable[p].adj;
  Edge* q;
  while(tmp != NULL){
    q = g->nodeTable[tmp->idx].adj;
    while(q != NULL && q->idx != g->NumVertices - 1){
      q = q->link;
    }
    q->idx = p;

    tmp = tmp->link;
  }
  g->NumVertices--;
}
//銷毀圖
void destroy_graph_link(GraphLink* g){
  //釋放所有邊的內存空間
  Edge* t = NULL;
  Edge* p = NULL;
  for(int i = 0; i< g->NumVertices; ++i){
    t = g->nodeTable[i].adj;
    while(NULL != t){
      p = t;
      t = t->link;
      free(p);
    }
  }

  //釋放所有頂點的內存空間
  free(g->nodeTable);
  g->nodeTable = NULL;
  g->MaxVertices = g->NumVertices = g->NumEdges = 0;
}

//取得指定頂點的第一個后序頂點
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;
}

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');
  //顯示圖
  //show_graph_link(&gl);

  //插入邊(尾插)
  /*
  insert_edge_tail(&gl, 'A', 'B');
  insert_edge_tail(&gl, 'A', 'D');
  insert_edge_tail(&gl, 'B', 'C');
  insert_edge_tail(&gl, 'B', 'E');
  insert_edge_tail(&gl, 'C', 'D');
  insert_edge_tail(&gl, 'C', 'E');
  */

  //插入邊(頭插)
  ///*
  insert_edge_head(&gl, 'A', 'B');
  insert_edge_head(&gl, 'A', 'D');
  insert_edge_head(&gl, 'B', 'C');
  insert_edge_head(&gl, 'B', 'E');
  insert_edge_head(&gl, 'C', 'D');
  insert_edge_head(&gl, 'C', 'E');
  //*/
  //顯示圖
  show_graph_link(&gl);

  printf("\n");

  //刪除邊
  remove_edge(&gl, 'A', 'D');
  //顯示圖
  show_graph_link(&gl);

  printf("\n");

  //刪除頂點
  remove_vertex(&gl, 'C');
  //顯示圖
  show_graph_link(&gl);

  //臨街頂點的下標
  int v = get_first_neighbor(&gl, 'B');
  printf("%d\n", v);
  v = get_next_neighbor(&gl, 'B', 'A');
  printf("%d\n", v);
  //銷毀圖
  destroy_graph_link(&gl);
}


免責聲明!

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



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