p354图的DFS(用栈消除递归调用)

首先看下面的递归代码,留意每层递归的栈需要保存什么变量

int dfsvisit(gve G,node *pnode,int *time)
{
    edge *tmp=pnode->next;
    (*time)++;
    pnode->d=*time;
    pnode->color=gray;
    while (tmp!=NULL)
    {
        if (G.g[tmp->i].color==white)
            dfsvisit(G,&G.g[tmp->i],time);
        tmp=tmp->next;
    }
    pnode->color=black;
    (*time)++;
    pnode->f=*time;
    return 0;
}
  • 递归呢,就是一个函数不断调用自身,直到满足递归终止条件而返回。系统在一个递归调用过程中,首先是将当前递归层的局部变量保存在当前栈里面,再将下一层递归的变量入栈;当下一层递归退出的时候,从栈中读取恢复这些局部变量,准备根据新的情况再进行操作(有可能又是递归调用);如果当前递归层的操作都做完了,系统就会出栈,要返回值的也在这个时候返回

那么对照着上面的代码看:

  • 首先看参数:
    • gve G,递归过程中并没有变化,相当于全局变量
    • node *pnode, 每层递归都不一样,需要保存在栈里面
    • int *time,时间戳,对递归来说是全局变量
  • 再看局部变量:
    • edge *tmp,函数会对和点相连的边逐一探索,每探索一次tmp的值都会发生变化,因此需要用栈来保存
  • 这样需要保存在栈里面的数据就确定了,pnode和tmp
  • 接下来是如何控制递归过程,分析while循环
    • 首先从栈里面恢复tmp,继续寻找下一条可用的边
    • then语句:如果没有可用的边了,准备出栈,从栈中恢复pnode,修改该点的属性(实际上pnode只在出栈的时候用得上)
    • else语句:如果有可用边,将tmp保存在栈里面,便于下次恢复,将下一层递归需要的参数入栈

下面这段代码可以完全替代上面的代码

typedef struct stack_element{
    node *pnode;
    edge *tmp;
}stack_element;
typedef struct stack{
    int size,tail;
    stack_element *head;
}stack;
int push(stack *visit_stack,node *pnode,edge *tmp)
{
    if (visit_stack->tail==visit_stack->size-1)
    {
        printf("stack overflow!\n");
        return 0;
    }
    visit_stack->tail++;
    visit_stack->head[visit_stack->tail].pnode=pnode;
    visit_stack->head[visit_stack->tail].tmp=tmp;
    return 0;
}
int pop(stack *visit_stack)
{
    visit_stack->tail--;
    return 0;
}
int dfsvisit(gve G,node *pnode,int *time)
{
    stack visit_stack;
    visit_stack.size=G.v;
    visit_stack.tail=-1;
    visit_stack.head=(stack_element *)malloc(sizeof(stack_element)*(G.v));
    edge *tmp=pnode->next;
    (*time)++;
    pnode->d=*time;
    pnode->color=gray;
    push(&visit_stack,pnode,tmp);
    while (visit_stack.tail!=-1)
    {
        tmp=visit_stack.head[visit_stack.tail].tmp;
        while ((tmp!=NULL)&&(G.g[tmp->i].color!=white))
            tmp=tmp->next;
        if (tmp==NULL)
        {
            pnode=visit_stack.head[visit_stack.tail].pnode;
            pnode->color=black;
            (*time)++;
            pnode->f=*time;
            pop(&visit_stack);
        }
        else
        {
            visit_stack.head[visit_stack.tail].tmp=tmp;
            push(&visit_stack,&G.g[tmp->i],G.g[tmp->i].next);
            (*time)++;
            visit_stack.head[visit_stack.tail].pnode->d=*time;
            visit_stack.head[visit_stack.tail].pnode->color=gray;
        }
    }
    free(visit_stack.head);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值