基于深度优先算法的有向图环路检测

1、digraph.h 

#ifndef _DIGRAPH_H_H
#define _DIGRAPH_H_H

#define ENABLE_DIGRAPH_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;      //邻接表
} DIGRAPH;

int  digraphCreate(DIGRAPH *pDigraph, int V);
int  reverseDigraphCreate(DIGRAPH* pSrcDigraph, DIGRAPH* pDstDigraph);
int  digraphDestroy(DIGRAPH *pDigraph);
int  V(DIGRAPH *pDigraph);
int  E(DIGRAPH *pDigraph);
int  addEdge(DIGRAPH *pDigraph, int x, int y);
void showDigraph(DIGRAPH *pDigraph);

#endif

2、digraph.c

#include <stdio.h>
#include <stdlib.h>
#include "digraph.h"

//有向图的数据结构

//当前图对象使用邻接表表示,大部分情况下,图中的所有顶点并非
//都是关联的,这种叫作稀疏图,使用邻接表来做为稀疏图的数据结
//构,可以节省很大的内存空间。如果以前了解过操作系统原理中内
//存机制的一级页表、二级页表机制,就会很快明白,为什么使用邻
//接表来表示稀疏图可以节省大部内存空间了。

//创建图对象,其中V表示最大顶点个数
int digraphCreate(DIGRAPH *pDigraph, int V)
{
    if ( pDigraph == NULL )
    {
        return -1; 
    }

    pDigraph->V = V;
    pDigraph->E = 0;
    pDigraph->adjTable = (ADJ_HEAD *)malloc(sizeof(ADJ_HEAD) * V);
    CHECK_NULL_AND_RET(pDigraph->adjTable);

    return 0;
}

//创建反向图
int reverseDigraphCreate(DIGRAPH* pSrcDigraph, DIGRAPH* pDstDigraph)
{
    int i = 0;

    if ( pSrcDigraph == NULL || pDstDigraph == NULL )
    {
        return -1; 
    }

    if ( digraphCreate(pDstDigraph, V(pSrcDigraph)) < 0 )
    {
        return -1; 
    }

    for ( i = 0; i < V(pSrcDigraph); i++ )
    {
        ADJ_ENTRY* pCurAdjEntry = (pSrcDigraph->adjTable + i)->entryHead;

        while ( pCurAdjEntry != NULL )
        {
            addEdge(pDstDigraph, pCurAdjEntry->adjoinPoint, i);
            pCurAdjEntry = pCurAdjEntry->pNext;
        }
    }

    return 0;
}

//销毁图对象
int digraphDestroy(DIGRAPH *pDigraph)
{
    int i = 0;

    if ( pDigraph == NULL )
    {
        return -1; 
    }

    for ( i = 0; i < V(pDigraph); i++ )
    {
        ADJ_ENTRY *pCurAdjEntry = (pDigraph->adjTable + i)->entryHead;

        while ( pCurAdjEntry != NULL )
        {
            ADJ_ENTRY *pFreeAdjEntry = pCurAdjEntry;
            pCurAdjEntry = pCurAdjEntry->pNext;

            free(pFreeAdjEntry);
        }
    }

    free(pDigraph->adjTable);

    pDigraph->V = 0;
    pDigraph->E = 0;
    pDigraph->adjTable = NULL;

    return 0;
}

//获取图对象的顶点个数
int V(DIGRAPH *pDigraph)
{
    if ( pDigraph == NULL )
    {
        return -1; 
    }

    return pDigraph->V;
}

//获取图对象的边数
int E(DIGRAPH *pDigraph)
{
    if ( pDigraph == NULL )
    {
        return -1; 
    }

    return pDigraph->E;
}

//邻接表添加条目
static int adjAdd(DIGRAPH *pDigraph, int x, int y)
{
    ADJ_HEAD  *pAdjHead = NULL;
    ADJ_ENTRY *pNewAdjEntry = NULL;

    if ( pDigraph == NULL )
    {
        return -1; 
    }

    if ( x >= pDigraph->V || x < 0 || y >= pDigraph->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 = (pDigraph->adjTable + x);

    pNewAdjEntry->pNext = pAdjHead->entryHead;
    pAdjHead->entryHead = pNewAdjEntry;

    return 0;
}

//向图对象中增加路径
int addEdge(DIGRAPH *pDigraph, int x, int y)
{
    if ( adjAdd(pDigraph, x, y) < 0 )
    {
        return -1; 
    }

    pDigraph->E++;

    return 0;
}

//显示图对象的信息
void showDigraph(DIGRAPH *pDigraph)
{
    int i = 0;

    if ( pDigraph == NULL )
    {
        return; 
    }

    printf("point count: %d\r\n", V(pDigraph));
    printf("edge  count: %d\r\n", E(pDigraph));
    printf("------------------\r\n");

    for ( i = 0; i < V(pDigraph); i++ )
    {
        ADJ_ENTRY* pCurEntry = (pDigraph->adjTable + i)->entryHead;

        while ( pCurEntry != NULL ) 
        {
            printf("%d --> %d\r\n", i, pCurEntry->adjoinPoint); 

            pCurEntry = pCurEntry->pNext;
        }
    }

    printf("------------------\r\n");
}

#if ENABLE_DIGRAPH_TEST
int main()
{
    DIGRAPH digraphObj = {0};
    DIGRAPH reverseDigraphObj = {0};

    digraphCreate(&digraphObj, 10);

    addEdge(&digraphObj, 0, 1);
    addEdge(&digraphObj, 0, 2);
    addEdge(&digraphObj, 0, 3);
    addEdge(&digraphObj, 0, 4);
    showDigraph(&digraphObj);

    reverseDigraphCreate(&digraphObj, &reverseDigraphObj);
    showDigraph(&reverseDigraphObj);

    digraphDestroy(&digraphObj);
    digraphDestroy(&reverseDigraphObj);

    return 0;
}
#endif

3、digraphCycle.c

#include "stdio.h"
#include "digraph.h"

#define CHECK_NULL_RET(x) { if ( (x) == NULL ) return -1; }

enum
{
    FALSE,
    TRUE
} E_BOOL;

int* gMarked = NULL;
int* gOnStack = NULL;
int  gIsCycle = FALSE;

//基于深度优先算法实现的有向图环路检测
void dfs(DIGRAPH* pDigraph, int s)
{
    ADJ_ENTRY* pCurAdjEntry = NULL;

    if ( s < 0 || s >= V(pDigraph) )
    {
        printf("invalid s %d\r\n", s);
        return; 
    }

    gMarked[s] = TRUE;

    gOnStack[s] = TRUE;

    pCurAdjEntry = (pDigraph->adjTable + s)->entryHead;
    while ( pCurAdjEntry != NULL )
    {
        if ( !gMarked[pCurAdjEntry->adjoinPoint] ) 
        {
            dfs(pDigraph, pCurAdjEntry->adjoinPoint); 
        }
        else if ( gOnStack[pCurAdjEntry->adjoinPoint] )
        {
            gIsCycle = TRUE;
            return;
        }

        pCurAdjEntry = pCurAdjEntry->pNext; 
    }

    //注意这里gOnStack与gMarked的区别,gMarked是深度优先算法所使用的
    //标记,记录当前该点是否走过,如果走过就选择其它点进行尝试。
    //而gOnStack表示从源点到当前点的路径,如果在遇到每条路不通的情况下,
    //需要退回到上个点,这时候gOnStack中就要撤销标记,如下示例,当走到
    //3的时候,此时gOnStack和gMarked一样,0~3的数组索引都标为TRUE,
    //但这时候已经没有路,需要退回到2,此时gOnStack[3]则为FALSE,这时候
    //发现2也没有其它可走的路,则退回到1,此时gOnStack[2]则为FALSE,
    //当从1走到4的时候,gOnStack只有索引0、1、4为TRUE,而gMarked则
    //索引0~4都为TRUE。
    //
    //示例:
    //0 --> 1 --> 2 --> 3
    //      |
    //      |---> 4 --> 5 
    gOnStack[s] = FALSE;
}

int main()
{
    int size = 0;
    DIGRAPH digraphObj = {0};

    //创建有向图对象
    digraphCreate(&digraphObj, 5);
    #if 0
    addEdge(&digraphObj, 0, 1);
    addEdge(&digraphObj, 0, 2);
    addEdge(&digraphObj, 1, 3);
    addEdge(&digraphObj, 2, 3);
    addEdge(&digraphObj, 3, 4);
    #else
    addEdge(&digraphObj, 0, 1);
    addEdge(&digraphObj, 0, 2);
    addEdge(&digraphObj, 1, 3);
    addEdge(&digraphObj, 2, 3);
    addEdge(&digraphObj, 3, 0);
    #endif
    showDigraph(&digraphObj);

    //资源分配
    size = sizeof(int) * V(&digraphObj);
    gMarked = (int *)malloc(size);
    CHECK_NULL_RET(gMarked);
    memset(gMarked, 0, size);
    gOnStack = (int *)malloc(size);
    CHECK_NULL_RET(gOnStack);
    memset(gOnStack, 0, size);

    //基于深度优先算法实现的有向图环路检测
    dfs(&digraphObj, 0);
    printf("Cycle: %s\r\n", gIsCycle ? "TRUE" : "FALSE" );

    //资源销毁
    free(gMarked);
    free(gOnStack);
    digraphDestroy(&digraphObj);

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值