广度优先搜索

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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值