1、queue.h
#ifndef _QUEUE_H_
#define _QUEUE_H_
#define ENABLE_QUEUE_TEST 0
typedef struct
{
int *data;
int head;
int tail;
int count;
int size;
} QUEUE;
int queueCreate(QUEUE* pQueue, int size);
int queueDestroy(QUEUE* pQueue);
int enqueue(QUEUE* pQueue, int val);
int dequeue(QUEUE* pQueue);
int isEmpty(QUEUE* pQueue);
#endif
2、queue.c
#include "stdio.h"
#include "queue.h"
int queueCreate(QUEUE* pQueue, int size)
{
if ( pQueue == NULL || size <= 0 )
{
return -1;
}
pQueue->head = 0;
pQueue->tail = 0;
pQueue->count = 0;
pQueue->size = size;
pQueue->data = (int *)malloc(sizeof(int) * size);
if ( pQueue->data == NULL )
{
return -1;
}
memset(pQueue->data, 0, sizeof(int) * size);
return 0;
}
int queueDestroy(QUEUE* pQueue)
{
if ( pQueue == NULL )
{
return -1;
}
if ( pQueue->data != NULL )
{
free(pQueue->data);
}
memset(pQueue, 0, sizeof(QUEUE));
return 0;
}
int enqueue(QUEUE* pQueue, int val)
{
if ( pQueue == NULL )
{
return -1;
}
if ( pQueue->count >= pQueue->size )
{
return -1;
}
pQueue->data[pQueue->tail] = val;
pQueue->tail = (pQueue->tail + 1) % pQueue->size;
pQueue->count++;
return 0;
}
int dequeue(QUEUE* pQueue)
{
int val = 0;
if ( pQueue == NULL )
{
return -1;
}
if ( pQueue->count <= 0 )
{
return -1;
}
val = pQueue->data[pQueue->head];
pQueue->head = (pQueue->head + 1) % pQueue->size;
pQueue->count--;
return val;
}
int isEmpty(QUEUE* pQueue)
{
if ( pQueue == NULL || pQueue->count <= 0 )
{
return 1;
}
return 0;
}
#if ENABLE_QUEUE_TEST
int main()
{
QUEUE q = {0};
queueCreate(&q, 5);
enqueue(&q, 1);
enqueue(&q, 2);
enqueue(&q, 3);
enqueue(&q, 4);
enqueue(&q, 5);
printf("%d\r\n", dequeue(&q));
printf("%d\r\n", dequeue(&q));
printf("%d\r\n", dequeue(&q));
printf("%d\r\n", dequeue(&q));
printf("%d\r\n", dequeue(&q));
printf("%d\r\n", dequeue(&q));
queueDestroy(&q);
return 0;
}
#endif
3、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
4、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
5、breadthFirstSearch.c
#include "stdio.h"
#include "graph.h"
#include "queue.h"
//广度优先搜索
//1 随便选择1个点为开始点,将该点加入到队列中,并标记该点已经走过
//2 遍历开始点所有关联的邻接点,将这些邻接点也都标记为走过,同时
// 将这些邻接点的关联邻接点加入到队列中
//3 从队列中移除一个节点(第一次为开始点,后续则为一些邻接点),
// 如果队列不为空,则将取出的节点做为开始点,进行2~3步的循环处
// 理,直接最终队列为空。
//广度优先搜索的核心思想是先遍历完开始点相关联的路径,只有这些路径
//都处理完成后,才遍历比开始点稍远一点的路径,依此类推,直到最终与
//当前开始点相关联的所有路径全部遍历完。
enum
{
FALSE,
TRUE,
} E_BOOL;
int* marked = NULL;
int* edgeTo = NULL;
QUEUE q = {0};
void bfsInit(GRAPH* pGraph)
{
marked = (int *)malloc(sizeof(int) * V(pGraph));
memset(marked, 0, sizeof(int) * V(pGraph));
edgeTo = (int *)malloc(sizeof(int) * V(pGraph));
memset(edgeTo, 0, sizeof(int) * V(pGraph));
queueCreate(&q, V(pGraph));
}
void bfsUninit()
{
if ( marked != NULL )
{
free(marked);
marked = NULL;
}
if ( edgeTo != NULL )
{
free(edgeTo);
edgeTo = NULL;
}
queueDestroy(&q);
}
//广度优先搜索核心函数
void bfs(GRAPH* pGraph, int s)
{
//将开始点加入到队列中,并标记该点已经走过
marked[s] = TRUE;
enqueue(&q, s);
printf("--> %d\r\n", s);
//当前图中与开始点相关联的所有点都已经走过,并且都已经处理过,则
//队列为空,搜索结束。
while ( !isEmpty(&q) )
{
//从队列中取出待处理的点。
//当一个点未走过时会加入到队列中,当一个点处理过后,则从队列中移除。
int curPoint = dequeue(&q);
ADJ_ENTRY *pCurEntry = (pGraph->adjTable + curPoint)->entryHead;
//遍历与待处理的点所有相关联的邻接点
while ( pCurEntry != NULL )
{
//如果这个邻接点没有走过,则标记为走过,同时加入到队列中
if ( !marked[pCurEntry->adjoinPoint] )
{
marked[pCurEntry->adjoinPoint] = TRUE;
enqueue(&q, pCurEntry->adjoinPoint);
edgeTo[pCurEntry->adjoinPoint] = curPoint;
printf("--> %d\r\n", pCurEntry->adjoinPoint);
}
pCurEntry = pCurEntry->pNext;
}
}
}
void generateGraph(GRAPH *pGraph)
{
addEdge(pGraph, 0, 1);
addEdge(pGraph, 0, 2);
addEdge(pGraph, 1, 3);
addEdge(pGraph, 1, 4);
addEdge(pGraph, 2, 3);
addEdge(pGraph, 2, 4);
}
int main()
{
GRAPH graph = {0};
graphCreate(&graph, 5);
generateGraph(&graph);
showGraph(&graph);
bfsInit(&graph);
bfs(&graph, 0);
bfsUninit();
graphDestroy(&graph);
return 0;
}