1、graph.h
#ifndef _GRAPH_H_H
#define _GRAPH_H_H
#define ENABLE_GRAPH_TEST 0
#define CHECK_NULL_AND_RET(x) { if((x) == NULL) return -1; }
typedef struct _ADJ_ENTRY
{
int adjoinPoint;
struct _ADJ_ENTRY* pNext;
} ADJ_ENTRY;
typedef struct
{
struct _ADJ_ENTRY* entryHead;
} ADJ_HEAD;
typedef struct
{
int V; //顶点数
int E; //边数
ADJ_HEAD* adjTable; //邻接表
} GRAPH;
int graphCreate(GRAPH *pGraph, int V);
int graphDestroy(GRAPH *pGraph);
int V(GRAPH *pGraph);
int E(GRAPH *pGraph);
int addEdge(GRAPH *pGraph, int x, int y);
void showGraph(GRAPH *pGraph);
#endif
2、graph.c
#include <stdio.h>
#include <stdlib.h>
#include "graph.h"
//无向图的数据结构
//当前图对象使用邻接表表示,大部分情况下,图中的所有顶点并非
//都是关联的,这种叫作稀疏图,使用邻接表来做为稀疏图的数据结
//构,可以节省很大的内存空间。如果以前了解过操作系统原理中内
//存机制的一级页表、二级页表机制,就会很快明白,为什么使用邻
//接表来表示稀疏图可以节省大部内存空间了。
//
//图示例:
//当前图有6个顶点,6条边
// 0
// / \
// 1 2
// | |
// 3 4
// \ /
// 5
//
//邻接表示例:
//其中有多少个顶点就有多少个数组成员,数组索引代表每个顶点。
//数组的值是一个链表,每个链表条目表示当前数组索引顶点所临接的点,
//即当前索引顶点与每个链表条目中的临接点相连构成一个边.
//
// [0]-->1-->2
// [1]-->0-->3
// [2]-->0-->4
// [3]-->1-->5
// [4]-->2-->5
// [5]-->3-->4
//创建图对象,其中V表示最大顶点个数
int graphCreate(GRAPH *pGraph, int V)
{
if ( pGraph == NULL )
{
return -1;
}
pGraph->V = V;
pGraph->E = 0;
pGraph->adjTable = (ADJ_HEAD *)malloc(sizeof(ADJ_HEAD) * V);
CHECK_NULL_AND_RET(pGraph->adjTable);
return 0;
}
//销毁图对象
int graphDestroy(GRAPH *pGraph)
{
int i = 0;
if ( pGraph == NULL )
{
return -1;
}
for ( i = 0; i < V(pGraph); i++ )
{
ADJ_ENTRY *pCurAdjEntry = (pGraph->adjTable + i)->entryHead;
while ( pCurAdjEntry != NULL )
{
ADJ_ENTRY *pFreeAdjEntry = pCurAdjEntry;
pCurAdjEntry = pCurAdjEntry->pNext;
free(pFreeAdjEntry);
}
}
free(pGraph->adjTable);
pGraph->V = 0;
pGraph->E = 0;
pGraph->adjTable = NULL;
return 0;
}
//获取图对象的顶点个数
int V(GRAPH *pGraph)
{
if ( pGraph == NULL )
{
return -1;
}
return pGraph->V;
}
//获取图对象的边数
int E(GRAPH *pGraph)
{
if ( pGraph == NULL )
{
return -1;
}
return pGraph->E;
}
//邻接表添加条目
static int adjAdd(GRAPH *pGraph, int x, int y)
{
ADJ_HEAD *pAdjHead = NULL;
ADJ_ENTRY *pNewAdjEntry = NULL;
if ( pGraph == NULL )
{
return -1;
}
if ( x >= pGraph->V || x < 0 || y >= pGraph->V || y < 0 )
{
return -1;
}
pNewAdjEntry = (ADJ_ENTRY *)malloc(sizeof(ADJ_ENTRY));
CHECK_NULL_AND_RET(pNewAdjEntry);
memset(pNewAdjEntry, 0, sizeof(ADJ_ENTRY));
pNewAdjEntry->adjoinPoint = y;
pAdjHead = (pGraph->adjTable + x);
pNewAdjEntry->pNext = pAdjHead->entryHead;
pAdjHead->entryHead = pNewAdjEntry;
return 0;
}
//向图对象中增加路径
int addEdge(GRAPH *pGraph, int x, int y)
{
if ( adjAdd(pGraph, x, y) < 0 )
{
return -1;
}
if ( adjAdd(pGraph, y, x) < 0 )
{
return -1;
}
pGraph->E++;
return 0;
}
//显示图对象的信息
void showGraph(GRAPH *pGraph)
{
int i = 0;
if ( pGraph == NULL )
{
return;
}
printf("point count: %d\r\n", V(pGraph));
printf("edge count: %d\r\n", E(pGraph));
printf("------------------\r\n");
for ( i = 0; i < V(pGraph); i++ )
{
ADJ_ENTRY* pCurEntry = (pGraph->adjTable + i)->entryHead;
while ( pCurEntry != NULL )
{
printf("%d --> %d\r\n", i, pCurEntry->adjoinPoint);
pCurEntry = pCurEntry->pNext;
}
}
printf("------------------\r\n");
}
#if ENABLE_GRAPH_TEST
int main()
{
GRAPH graphObj = {0};
graphCreate(&graphObj, 10);
addEdge(&graphObj, 0, 1);
addEdge(&graphObj, 1, 2);
showGraph(&graphObj);
graphDestroy(&graphObj);
return 0;
}
#endif
3、depthFirstSearch.c
#include "stdio.h"
#include "graph.h"
//深度优先搜索
//1 首先选择任意点为源点
//2 记载当前源点已经被走过。
//3 之后,遍历当前点的所有临接点,如果对应临接点没有被
// 标记走过,则将此临接点做为源点,重复第2、3步,直到
// 图中所有关联的点都被走过。
enum
{
FALSE,
TRUE,
} E_BOOL;
int* marked = NULL;
int count = 0;
void initMarked(int s)
{
int size = sizeof(int) * s;
marked = (int *)malloc(size);
memset(marked, 0, size);
}
void dfs(GRAPH *pGraph, int v)
{
ADJ_ENTRY *pCurEntry = NULL;
marked[v] = TRUE;
count++;
printf("--> %d\r\n", v);
pCurEntry = (pGraph->adjTable + v)->entryHead;
while ( pCurEntry != NULL )
{
if ( !marked[pCurEntry->adjoinPoint] )
{
dfs(pGraph, pCurEntry->adjoinPoint);
}
pCurEntry = pCurEntry->pNext;
}
}
void generateGraph(GRAPH *pGraph)
{
addEdge(pGraph, 0, 1);
addEdge(pGraph, 1, 2);
addEdge(pGraph, 2, 3);
addEdge(pGraph, 3, 4);
}
int main()
{
GRAPH graph = {0};
graphCreate(&graph, 5);
generateGraph(&graph);
showGraph(&graph);
initMarked(V(&graph));
dfs(&graph, 0);
printf("pass count %d\r\n", count);
graphDestroy(&graph);
return 0;
}