图的算法DFS、BFS、Prim、Kruskal

本文介绍了图的深度优先遍历(DFS)和广度优先遍历(BFS)以及两种最小生成树算法:Prim和Kruskal。通过示例代码详细解释了这些算法的工作原理和实现步骤,并在最后给出了一个图的实例来演示算法的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//图的深度优先遍历、广度优先遍历
//最小生成树算法:Prim、Kruskal
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <deque>
#include <set>

#define MAXVEX 100 //最大定点个数
#define INFINITY 65535  //无穷大
struct Graph
{
    char vertex[MAXVEX];
    int arc[MAXVEX][MAXVEX];
    int numVertexs, numEdges;
};

struct Edge
{
    int begin;
    int end;
    int weight;
};

struct COMP
{
    bool operator()(const Edge &e1, const Edge &e2)
    {
        return e1.weight < e2.weight;
    }
};
int visit[MAXVEX];
void DFS(Graph &G, int i)
{
    visit[i] = 1;
    std::cout << G.vertex[i] << std::endl;
    for(int j = 0; j < G.numVertexs; ++j)
    {
        if(G.arc[i][j] == 1 && !visit[j])
        {
            DFS(G, j);
        }
    }
}

void BFS(Graph &G)
{
    std::deque<int> d;
    for(int i = 0; i < G.numVertexs; ++i)
    {
        if(!visit[i])
        {
            visit[i] = 1;
            d.push_back(i);
            std::cout << G.vertex[i] << std::endl;
            while(!d.empty())
            {
                int j = d.front();
                d.pop_front();
                for(int k = 0; k < G.numVertexs; ++k)
                {
                    if(G.arc[j][k] == 1 && !visit[k])
                    {
                        visit[k] = 1;
                        std::cout << G.vertex[k] << std::endl;
                        d.push_back(k);
                    }
                }
            }
        }
    }
}

//Prim算法生成最小生成树
void MiniSpanTree_Prim(Graph &G)
{
    //将图中顶点进行划分成两部分,一部分是生成树,剩余的是图的其余顶点
    //首先将起始顶点0加入生成树部分,然后逐步从剩余的图中选择与生成树部分连接权重最小的顶点加入
    //直至n个顶点都加入生成树,此时有n-1条边,最小生成树生成
    int vertexNum = G.numVertexs;
    std::vector<int> flagVec(vertexNum, 0);//标记是否被考察
    int size = vertexNum;
    std::vector<int> key(vertexNum, INFINITY);
    std::vector<int> parent(vertexNum, 0);//标记每个节点的父节点
    key[0] = 0;
    parent[0] = -1;
    while(size > 0)
    {
        --size;
        int start = 0;
        int min = INFINITY;
        for(int i = 0; i < vertexNum; ++i)
        {
            if(!flagVec[i] && min > key[i])
            {
                start = i;
                min = key[i];
            }
        }
        flagVec[start] = 1;
        for(int i = 0; i < vertexNum; ++i)
        {
            if(!flagVec[i] && G.arc[start][i] < key[i])
            {
                key[i] = G.arc[start][i];
                parent[i] = start;
            }
        }
    }

    for(int i = 1; i < vertexNum; ++i)
    {
        int j = parent[i];
        std::cout << i << ", " << j << " " << G.arc[j][i] << std::endl;
    }

}

int Find(std::vector<int> &parent, int i)
{
    //最后一个连通节点
    while(parent[i] != -1)
    {
        i = parent[i];
    }
    return i;
}

int FindSet(std::vector<std::set<int>> &set, int i)
{
    for(int j = 0; j < set.size(); ++j)
    {
        if(set[j].find(i) != set[j].end())
        {
            return j;
        }
    }
    return -1;
}

void UnionSet(std::vector<std::set<int>> &set, int n, int m)
{
    //将集合n和集合m进行合并
    for(std::set<int>::iterator it = set[m].begin(); it != set[m].end(); ++it)
    {
        set[n].insert(*it);
    }
    std::vector<std::set<int>>::iterator iter = set.begin();
    set.erase(iter + m);
}
void MiniSpanTree_Kruskal(Graph &G)
{
    std::vector<Edge> edgeVec;
    for(int i = 0; i < G.numVertexs; ++i)
    {
        for(int j = i + 1; j < G.numVertexs; ++j)
        {
            if(G.arc[i][j] != INFINITY)
            {
                Edge e;
                e.begin = i;
                e.end = j;
                e.weight = G.arc[i][j];
                edgeVec.push_back(e);
            }
        }
    }

    std::vector<int> parent(G.numVertexs, -1);//记录各生成树中的节点
    std::sort(edgeVec.begin(), edgeVec.end(), COMP());
    std::vector<int> flagVec(G.numVertexs, 0);

    for(int i = 0; i < G.numEdges; ++i)
    {
        Edge &e = edgeVec[i];
        int start = e.begin;
        int end = e.end;
        //需要判断start和end是否在同一棵树中,若是,则舍弃这条边;否则,将这两棵树连在一起
        int n = Find(parent,start);
        int m = Find(parent, end);
        if(n != m)
        {
            //将这两个连通分支进行合并
            parent[n] = m;
            std::cout << start << "," << end << "  " << G.arc[start][end] << std::endl;
        }
    }

    std::vector<std::set<int>> set;
    for(int i = 0; i < G.numEdges; ++i)
    {
        Edge &e = edgeVec[i];
        int n = FindSet(set, e.begin);//查找e.begin属于的集合
        int m = FindSet(set, e.end);
        if(n != m)
        {
            //n和m没有在同一个集合中,进行合并
            std::cout << e.begin << "," << e.end << " " << e.weight << std::endl;
            if(n != -1 && m == -1)
            {
                //将e.end插入到n集合中
                set[n].insert(e.end);
            }
            else if(n == -1 && m != -1)
            {
                //将e.begin插入到m集合中
                set[m].insert(e.begin);
            }
            else if(n == -1 && m == -1)
            {
                //新增集合
                std::set<int> tmp;
                tmp.insert(e.begin);
                tmp.insert(e.end);
                set.push_back(tmp);
            }
            else if(n != -1 && m != -1)
            {
                //将集合n和集合m进行合并
                UnionSet(set, n, m);
            }

        }
    }
}
int main(int nArgs, char* pArg[])
{
    Graph G;
    G.numVertexs = 9;
    G.numEdges = 15;

    for(int i = 0; i < G.numVertexs; ++i)
    {
        G.vertex[i] = i;
    }

    for(int i = 0; i < G.numVertexs; ++i)
    {
        for(int j = 0; j < G.numVertexs; ++j)
        {
            G.arc[i][j] = INFINITY;
        }
    }
    G.arc[0][1] = G.arc[1][0] = 10;
    G.arc[0][5] = G.arc[5][0] = 11;
    G.arc[1][2] = G.arc[2][1] = 18;
    G.arc[1][6] = G.arc[6][1] = 16;
    G.arc[1][8] = G.arc[8][1] = 12;
    G.arc[2][3] = G.arc[3][2] = 22;
    G.arc[2][8] = G.arc[8][2] = 8;
    G.arc[3][4] = G.arc[4][3] = 20;
    G.arc[3][6] = G.arc[6][3] = 24;
    G.arc[3][7] = G.arc[7][3] = 16;
    G.arc[3][8] = G.arc[8][3] = 21;
    G.arc[4][5] = G.arc[5][4] = 26;
    G.arc[4][7] = G.arc[7][4] = 7;
    G.arc[5][6] = G.arc[6][5] = 17;
    G.arc[6][7] = G.arc[7][6] = 19;

    //MiniSpanTree_Prim(G);
    MiniSpanTree_Kruskal(G);
    system("pause");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值