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);
}
