图的基础算法-广度优先搜索/深度优先搜索

图有矩阵存储和链表存储两种。这里采用链表存储。
参考《算法导论》上面的做法,首先定义图结点的结构。为了跟踪算法的进展,广度优先搜索在概念上将每个结点涂成白色。在算法推进过程中,结点的颜色可能变成灰色或者黑色。在搜索过程中,第一次遇到一个结点时,表示该结点已被发现,此时该结点的颜色将从白色变成灰色。灰色或黑色结点都是已经被发现过的结点。所有与黑色结点邻接的结点都已经被发现。对于灰色结点来说,其邻接结点中可能存在未被发现的白色结点。

struct graphNode {
    int ver;
    //为结点定义颜色,方便在遍历树的时候,标记结点是否已经访问。
    //white表示还没有访问过的结点
    //gray表示已经访问过的结点(结点一旦被访问,就设置color为“gray”)
    //black表示该节点的邻接结点都已访问过,由gray变成black
    string color; 
    //遍历过程中记录该结点的父结点
    graphNode* peer;
    //遍历过程记录该结点的深度
    int dest;
    //stime是遍历该结点的起始时间,ftime该结点的邻接结点遍历完成回到该结点的时间(用于深度优先搜索)
    int stime;
    int ftime;
    graphNode() {
        color = "white";
        peer = NULL;
        dest = 0;
        stime = 0;
        ftime = 0;
    }
    graphNode(int v):ver(v) {
        color = "white";
        peer = NULL;
        dest = 0;
        stime = 0;
        ftime = 0;
    }
    graphNode(graphNode &g) {
        ver = g.ver;
        color = g.color;
        peer = g.peer;
        dest = g.dest;
        stime = g.stime;
        ftime = g.ftime;
    }
};

BFS
在执行广度优先搜索的过程中将构造出一棵广度优先树。一开始树中只有根结点s,在扫描已发现结点u的邻接链表时,每当发现一个白色结点v,就将白色结点v和边(u,v)同时加入该树里面。在广度优先树中,u是v的父结点。
首先选定源结点s作为根结点,从源结点开始遍历。利用队列来管理灰色结点。

广度优先搜索能够正确计算出最短路径距离

void BFSearch(linkedgraph &g, int v) {
    arrayQueue<graphNode*> q;
    graphNode *s = &g.gnode[v-1];
    s->color = "gray";
    //将源结点插入队列
    q.push(s);
    while (q.empty() == false) {
        graphNode *u = q.front();
        int size = g.gchain[u->ver - 1].size();
        //遍历队列首项的结点的邻接链表中所有的结点
        for (int i = 1; i <= size; i++) {
            graphNode *v = g.gchain[u->ver - 1].get(i);
            if (v->color == "white") {
                v->color = "gray";
                v->peer = u;
                v->dest = u->dest + 1;
                cout << v->ver << endl;
                q.push(v);
            }
        }
        //遍历完该结点的邻接结点后,将该结点的color改为“black”,然后删除队列中该结点
        u->color = "black";
        q.pop();
    }
    return;
}

DFS
深度优先搜索总是对最近才发现的结点v的出发边进行探索,直到该结点所有出发边都被发现为止。一旦结点v的所有出发边都被发现为止。一旦结点的所有出发边都被发现,搜索则“回溯”到v的前驱结点(v是经过该结点才被发现的),来搜索该前驱结点的出发边。该过程一直持续到从源结点可以到达的所有结点都被发现为止。

void DFSvisit(linkedgraph &g, graphNode* s,int &time) {
    time++;
    s->color = "gray";
    s->stime = time;
    int size = g.gchain[s->ver - 1].size();
    for (int i = 1; i <= size; i++) {
        graphNode* v = g.gchain[s->ver - 1].get(i);
        if (v->color == "white") {
            v->peer=u;
            //递归遍历
            DFSvisit(g, v, time);
        }
    }
    s->color = "black";
    time++;
    s->ftime = time;
    cout << s->stime << " " << s->ftime << endl;
    return;
}

void DFSearch(linkedgraph &g, int v) {
    graphNode* s = &g.gnode[v - 1];
    int time = 0;
    DFSvisit(g, s,time);
    return;
}

代码的实现细节是针对笔者实现的图的类的相关接口来编写的。所以读者可能看不太懂代码,可以留言向笔者索要源代码,欢迎大家交流讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值