DFS非递归实现搜索图中两顶点间的所有路径

搜索无向图或有向图中两顶点间的所有最短路径应当使用DFS,配以适当的回溯操作即可实现路径搜索,具体代码如下,完全使用非递归方法实现

#include <iostream>
#include <vector>
#include <stdio.h>
#include <malloc.h>
#define N 5 //无环单边非负权重无向图顶点数

using namespace std;

bool Enable(int start, int i, int j, bool p[][N], bool node[], int& edgeLinkRootUsed) //检查j是否是i的下一可达顶点, 是返回1否则返回0
{
    if (p[i][j] == false)
        return false;

    if (node[j])
        return false;

    if (j == start && edgeLinkRootUsed == i)
        return false;

    return true;
}

int Search(int start, int k, int option, bool p[][N], bool node[], int& edgeLinkRootUsed)  //在顶点k上搜索顶点option后的第一个可达顶点,搜索成功返回顶点标号,否则返回-1
{
    int m = option;

    for (m++; m < N; m++)
    {
        if (Enable(start, k, m, p, node, edgeLinkRootUsed))
            return m;
    }
    return -1;
}

void FindRoad(bool isDiGraph, int start, int end, bool p[][N], int q[][N])  //路径搜索函数,寻找start和end间的所有路径
{
    int i, k;   //i为当前顶点,k为下一可达顶点
    int interval;
    int RoadLength;  //路径长度
    int count;      //路径计数
    bool node[N] = { 0 };  //Node数组标记各顶点在搜索过程中是否已被访问,Node[i]=0表示i+1顶点未被访问,Node[i]=1表示i+1顶点已被访问,这里首先初始化Node数组
    int edgeLinkRootUsed = -1;
    vector<int> path_list;

    count = 0;      //计数变量初始化
    if (start != end)
        node[start] = 1; //start标记为已访问
    i = start; k = -1;  //i初始化为起始顶点
    while (true)
    {
        if ((interval = Search(start, i, k, p, node, edgeLinkRootUsed)) == -1)   //搜索从k起的下一个可达顶点失败
        {
            if (i == start)    //路径搜索完毕,退出
                break;

            if (k != -1)
            {
                path_list.pop_back();
            }
        }
        else
        {
            //搜索出下一可达顶点
            if (k == -1)
            {
                path_list.push_back(i);           //建立表示当前顶点i的路径节点                //下一可达顶点标记为已访问  
            }
            node[interval] = true;                                 //下一可达顶点标记为已访问

            if (i == start && isDiGraph == false)
            {
                edgeLinkRootUsed = interval;
            }
            i = interval;     //更新i为下一可达顶点

            if (i == end)    //到达终点
            {
                RoadLength = 0;
                count++;                                 //路径计数变量自增
                cout << "第" << count << "条路径" << endl;
                size_t run = 0;
                for (; run < path_list.size(); ++run)   /*输出找到的路径*/
                {
                    cout << "V" << path_list[run] + 1 << "->";
                    if (run != 0)
                    {
                        RoadLength += q[path_list[run - 1]][path_list[run]];
                    }
                }

                cout << "V" << end + 1 << endl;
                cout << "路径长度" << RoadLength + q[path_list[run - 1]][end] << endl;    //输出找到的路径长度
            }
            else
            {
                k = -1;           //k重置 
                continue;
            }
        }
        node[i] = false;
        k = i;    //回溯
        i = path_list.back();
    }
    cout << "共有" << count << "条从V" << start + 1 << "到V" << end + 1 << "的路径" << endl;  //输出找到的路径总数
}

int main()
{
    bool isDiGaph = false;
    int m, n;  //m为起始顶点,n为终点
    bool p[N][N] = { 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0 };   //初始化邻接矩阵p
    int q[N][N] = { 0, 3, 0, 7, 8, 3, 0, 4, 0, 9, 0, 4, 0, 9, 2, 7, 0, 9, 0, 9, 8, 9, 2, 9, 0 };   //初始化权重矩阵q,q[i][j]为连接i和j的边的权重
    cout << "请输入要搜索的路径的起始顶点标号:" << endl;
    cin >> m;           //输入起始顶点标号

    cout << "请输入要搜索的路径的终点标号:" << endl;
    cin >> n;           //输入终点标号

    FindRoad(isDiGaph, m - 1, n - 1, p, q);   //搜索m和n之间的所有路径并输出
    return 0;
}

对于如下的无向图:

 其邻接矩阵和权重矩阵已在程序中数组的初始化列表中给出,程序运行时起始顶点输入为V1,终点输入为V3,则程序运行结果如下:

如果表示图的数据结构采用邻接链表则代码如下:

#include <iostream>
#include <vector>
#include <list>
#include <tuple>
#include <stdio.h>
#include <malloc.h>

using namespace std;

struct edge
{
    int weight;
    int end;
    edge(int w, int e) :weight(w), end(e) {}
};

struct adjacency_list
{
    void insert(int u, int v, int weight) { adj[u].push_back(edge(weight, v)); if (isDiGraph == false) adj[v].push_back(edge(weight, u)); }
    vector<list<edge>> adj;
    bool isDiGraph;
    adjacency_list(size_t v_num, bool id) :adj(v_num), isDiGraph(id) {}
};


bool Enable(int start, int i, const list<edge>::const_iterator &j, bool node[], int& edgeLinkRootUsed) //检查j是否是i的下一可达顶点, 是返回1否则返回0
{

    if (node[j->end])
        return false;

    if (j->end == start && edgeLinkRootUsed == i)
        return false;

    return true;
}

list<edge>::const_iterator Search(const adjacency_list& adj ,int start, int k, const list<edge>::const_iterator& option, bool node[], int& edgeLinkRootUsed)  //在顶点k上搜索顶点option后的第一个可达顶点,搜索成功返回顶点标号,否则返回-1
{
    list<edge>::const_iterator m = option;
    if (option == adj.adj[k].end())
        m = adj.adj[k].begin();
    else
        ++m;

    for (; m != adj.adj[k].end(); ++m)
    {
        if (Enable(start, k, m, node, edgeLinkRootUsed))
            return m;
    }
    return m;
}

#define N 5 //无环单边图顶点数

void FindRoad(const adjacency_list &adj, int start, int end)  //路径搜索函数,寻找start和end间的所有路径
{
    int i;   //i为当前顶点,k为下一可达顶点
    list<edge>::const_iterator interval, k;
    int RoadLength;  //路径长度
    int count;      //路径计数
    bool node[N] = { 0 };  //Node数组标记各顶点在搜索过程中是否已被访问,Node[i]=0表示i+1顶点未被访问,Node[i]=1表示i+1顶点已被访问,这里首先初始化Node数组
    int edgeLinkRootUsed = -1;
    vector<list<edge>::const_iterator> path_list;

    count = 0;      //计数变量初始化
    if (start != end)
        node[start] = 1; //start标记为已访问,
    i = start; k = adj.adj[start].cend();  //i初始化为起始顶点
    while (true)
    {
        if ((interval = Search(adj, start, i, k, node, edgeLinkRootUsed)) == adj.adj[i].cend())   //搜索从k起的下一个可达顶点失败
        {
            if (i == start)    //路径搜索完毕,退出
                break;

            if (k != adj.adj[i].cend())
            {
                path_list.pop_back();
            }
        }
        else
        {
            //搜索出下一可达顶点
            if (k == adj.adj[i].cend())
            {
                path_list.push_back(interval);           //建立表示当前顶点i的路径节点 
            }
            else
            {
                path_list.back() = interval;
            }
            node[interval->end] = true;                                 //下一可达顶点标记为已访问

            if (i == start && adj.isDiGraph == false)
            {
                edgeLinkRootUsed = interval->end;
            }
            i = interval->end;     //更新i为下一可达顶点

            if (i == end)    //到达终点
            {
                RoadLength = 0;
                count++;                                 //路径计数变量自增
                cout << "第" << count << "条路径" << endl;
                size_t run = 0;
                cout << "V" << start + 1 << "->";
                for (; run < path_list.size(); ++run)   /*输出找到的路径*/
                {
                    cout << "V" << path_list[run]->end + 1;
                    if (run < path_list.size() - 1)
                        cout << "->";
                    RoadLength += path_list[run]->weight;
                }

                cout << "路径长度" << RoadLength << endl;    //输出找到的路径长度
            }
            else
            {
                k = adj.adj[i].cend();           //k重置 
                continue;
            }
        }
        node[i] = false;
        k = path_list.back();    //回溯
        if (path_list.end() - 1 == path_list.begin())
        {
            i = start;
        }
        else
        {
            i = (*(path_list.end() - 2))->end;
        }
       
    }
    cout << "共有" << count << "条从V" << start + 1 << "到V" << end + 1 << "的路径" << endl << endl;  //输出找到的路径总数
}

int main()
{
    bool isDiGaph = false;
    int m, n;  //m为起始顶点,n为终点
    vector<tuple<int, int, int>> edge_info = { {0, 1, 3}, {0, 3, 7}, {0, 4, 8},{1, 4, 9}, {1, 2, 4}, {2, 4, 2}, {2, 3, 9}, {3, 4, 9} };
    adjacency_list adj(N, isDiGaph);
    for (auto& run : edge_info)
    {
        adj.insert(get<0>(run), get<1>(run), get<2>(run));
    }
    cout << "请输入要搜索的路径的起始顶点标号:" << endl;
    cin >> m;           //输入起始顶点标号

    cout << "请输入要搜索的路径的终点标号:" << endl;
    cin >> n;           //输入终点标号

    FindRoad(adj, m - 1, n - 1);   //搜索m和n之间的所有路径并输出
    return 0;
}

如果要找出所有简单环,则只要稍作修改即可

#include <iostream>
#include <vector>
#include <list>
#include <tuple>
#include <stdio.h>
#include <malloc.h>

using namespace std;

struct edge
{
    int weight;
    int end;
    edge(int w, int e) :weight(w), end(e) {}
};

struct adjacency_list
{
    void insert(int u, int v, int weight) { adj[u].push_back(edge(weight, v)); if (isDiGraph == false) adj[v].push_back(edge(weight, u)); }
    vector<list<edge>> adj;
    bool isDiGraph;
    adjacency_list(size_t v_num, bool id) :adj(v_num), isDiGraph(id) {}
};


bool Enable(int start, int i, const list<edge>::const_iterator& j, bool node[], int& edgeLinkRootUsed) //检查j是否是i的下一可达顶点, 是返回1否则返回0
{

    if (node[j->end])
        return false;

    if (j->end == start && edgeLinkRootUsed == i)
        return false;

    return true;
}

list<edge>::const_iterator Search(const adjacency_list& adj, int start, int k, const list<edge>::const_iterator& option, bool node[], int& edgeLinkRootUsed)  //在顶点k上搜索顶点option后的第一个可达顶点,搜索成功返回顶点标号,否则返回-1
{
    list<edge>::const_iterator m = option;
    if (option == adj.adj[k].end())
        m = adj.adj[k].begin();
    else
        ++m;

    for (; m != adj.adj[k].end(); ++m)
    {
        if (Enable(start, k, m, node, edgeLinkRootUsed))
            return m;
    }
    return m;
}

#define N 5 //无环单边图顶点数

void FindRoad(const adjacency_list& adj, int start, int end, bool node[], int &count)  //路径搜索函数,寻找start和end间的所有路径
{
    int i;   //i为当前顶点,k为下一可达顶点
    list<edge>::const_iterator interval, k;
    int RoadLength;  //路径长度
    int edgeLinkRootUsed = -1;
    vector<list<edge>::const_iterator> path_list;

    if (start != end)
        node[start] = 1; //start标记为已访问,
    i = start; k = adj.adj[start].cend();  //i初始化为起始顶点
    while (true)
    {
        if ((interval = Search(adj, start, i, k, node, edgeLinkRootUsed)) == adj.adj[i].cend())   //搜索从k起的下一个可达顶点失败
        {
            if (i == start)    //路径搜索完毕,退出
                break;

            if (k != adj.adj[i].cend())
            {
                path_list.pop_back();
            }
        }
        else
        {
            //搜索出下一可达顶点
            if (k == adj.adj[i].cend())
            {
                path_list.push_back(interval);           //建立表示当前顶点i的路径节点 
            }
            else
            {
                path_list.back() = interval;
            }
            node[interval->end] = true;                                 //下一可达顶点标记为已访问

            if (i == start && adj.isDiGraph == false)
            {
                edgeLinkRootUsed = interval->end;
            }
            i = interval->end;     //更新i为下一可达顶点

            if (i == end)    //到达终点
            {
                RoadLength = 0;
                count++;                                 //路径计数变量自增
                cout << "第" << count << "条简单环" << endl;
                size_t run = 0;
                cout << "V" << start + 1 << "->";
                for (; run < path_list.size(); ++run)   /*输出找到的路径*/
                {
                    cout << "V" << path_list[run]->end + 1;
                    if (run < path_list.size() - 1)
                        cout << "->";
                    RoadLength += path_list[run]->weight;
                }

                cout << "简单环长度" << RoadLength << endl;    //输出找到的路径长度
            }
            else
            {
                k = adj.adj[i].cend();           //k重置 
                continue;
            }
        }
        node[i] = false;
        k = path_list.back();    //回溯
        if (path_list.end() - 1 == path_list.begin())
        {
            i = start;
        }
        else
        {
            i = (*(path_list.end() - 2))->end;
        }

    }
}

int main()
{
    bool isDiGaph = false;
    int m, n;  //m为起始顶点,n为终点
    vector<tuple<int, int, int>> edge_info = { {0, 1, 3}, {0, 3, 7}, {0, 4, 8},{1, 4, 9}, {1, 2, 4}, {2, 4, 2}, {2, 3, 9}, {3, 4, 9} };
    adjacency_list adj(N, isDiGaph);
    for (auto& run : edge_info)
    {
        adj.insert(get<0>(run), get<1>(run), get<2>(run));
    }

    bool node[N] = { 0 };
    int count = 0;
    for (int i = 0; i < N; ++i)
    {
        FindRoad(adj, i, i, node, count);
        node[i] = true;
    }
    cout << "共有" << count << "条简单环" << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值