图论基础(邻接矩阵,邻接表,深度优先遍历,连通分量)的实现

news/2024/7/15 19:47:35 标签: 图论, 算法, dfs, 数据结构, c++

DenseGraph.h.表示邻接矩阵实现的图,一般邻接矩阵用于较为稠密的图

#ifndef DenseGraph_h
#define DenseGraph_h

#include <iostream>
#include <vector>
#include <cassert>

using namespace std;
//稠密图 --邻接矩阵
class DenseGraph
{
private:
    int n,m;//n是节点,m是边数
    bool directed;//表示是否是有向图
    vector<vector<bool>> g;//用一个二维的vector表示邻接矩阵
    
public:
    DenseGraph(int n,bool directed)//初始状态为矩阵内全为false,表示都不相连
    {
        this->n=n;
        this->directed=directed;
        this->m=0;
        for(int i=0;i<n;i++)
        {
            g.push_back(vector<bool>(n,false));
        }
    }
    
    ~DenseGraph()
    {
        
    }
    
    int V(){return n;}//获得节点的个数
    int E(){return m;}//或者边的条数
    
    void addEdge(int v,int w)
    {
        assert(v>=0 && v<n);
        assert(w>=0 && w<n);
        if(hasEdge(v,w))
            return;
        g[v][w]=true;
        if(!directed)
        {
            g[w][v]=true;
        }
        m++;
    }
    bool hasEdge(int v,int w)
    {
        assert(v>=0 && v<n);
        assert(w>=0 && w<n);
        return g[v][w];
    }
    //为图专门设计的迭代器,可以访问某个节点的与之相连接的下一个节点
    class adjIterator
    {
    private:
        DenseGraph &G;
        int v;
        int index;//节点的下标索引
    public:
        adjIterator(DenseGraph &graph,int v)
        :G(graph)
        {
            this->v=v;
            this->index=-1;
        }
        int begin()
        {
            index=-1;
            return next();//找到第一个不为0的节点
        }
        int next()
        {
            for(index+=1;index<G.V();index++)
            {
                if(G.g[v][index])
                    return index;
            }
            return -1;
        }
        bool end()
        {
            return index>=G.V();
        }
    };
};
#endif /* DenseGraph_h */

SparseGraph.h表示稀疏图,一般稀疏图用邻接表表示

#ifndef SparseGraph_h
#define SparseGraph_h

#include <iostream>
#include <vector>
#include <cassert>

using namespace std;
//邻接表--稀疏图
//在遍历邻边的时候,用邻接表时间复杂度为O(k),k为邻边的个数
//要是用邻接矩阵,时间复杂度为O(v),v为所有的顶点个数
class SparseGraph
{
private:
    int n,m;
    bool directed;
    vector<vector<int>> g;
public:
    SparseGraph(int n,bool directed)
    {
        this->n=n;
        this->m=0;
        this->directed=directed;
        for(int i=0;i<n;i++)
        {
            g.push_back(vector<int>());
        }
    }
    ~SparseGraph(){}
    
    int V(){return n;}
    int E(){return m;}
    
    void addEdge(int v,int w)
    {
        assert(v>=0 && v<n);
        assert(w>=0 && w<n);
        if(hasEdge(v, w))
            return;
        g[v].push_back(w);
        if(v!=w && !directed)
        {
            g[w].push_back(v);
        }
        m++;
    }
    bool hasEdge(int v,int w)
    {
        assert(v>=0 && v<n);
        assert(w>=0 && w<n);
        for(int i=0;i<g[v].size();i++)
        {
            if(g[v][i]==w)
            {
                return true;
            }
        }
        return false;
    }

    class adjIterator
    {
    private:
        SparseGraph &G;
        int v;
        int index;
    public:
        adjIterator(SparseGraph &graph,int v)
        :G(graph)
        {
            this->v=v;
            this->index=0;
        }
        int begin()
        {
            index=0;
            if(G.g[v].size())
            {
                return G.g[v][index];
            }
            return -1;
        }
        int next()
        {
            index++;
            if(index<G.g[v].size())
            {
                return G.g[v][index];
            }
            return -1;
        }
        bool end()
        {
            return index >= G.g[v].size();
        }
    };
};

#endif /* SparseGraph_h */

Component.h表示用深度优先遍历实现的计算连通分量的算法

#ifndef Component_h
#define Component_h
#include <iostream>
#include <cassert>

using namespace std;
template<typename Graph>
class Component
{
private:
    Graph &G;
    bool *visited;//标记某个节点是否已经被遍历
    int ccount;//联通分量的个数
    
    void dfs(int v)
    {
        visited[v]=true;
        
        typename Graph::adjIterator adj(G,v);
        for(int i=adj.begin();!adj.end();i=adj.next())
        {
            if(!visited[i])
            {
                dfs(i);
            }
        }
    }
public:
    Component(Graph &graph)
    :G(graph)
    {
        visited=new bool[G.V()];
        ccount=0;
        for(int i=0;i<G.V();i++)
            visited[i]=false;
        
        for(int i=0;i<G.V();i++)
        {
            if(!visited[i])
            {
                dfs(i);             //深度优先遍历
                ccount++;           //联通分量
            }
        }
    }
    
    ~Component()
    {
        delete []visited;
    }
    int count()
    {
        return ccount;
    }
};

#endif /* Component_h */

Path.h计算节点的路径

#ifndef Path_h
#define Path_h
#include <iostream>
#include <cassert>
#include <stack>
#include <vector>
using namespace std;

template<typename Graph>
class Path
{
private:
    Graph &G;
    int s;
    bool *visited;
    int *from;
    void dfs(int v)
    {
        visited[v]=true;
        
        typename Graph::adjIterator adj(G,v);
        for(int i=adj.begin();!adj.end();i=adj.next())
        {
            if(!visited[i])
            {
                from[i]=v;
                dfs(i);
            }
        }
    }
public:
    Path(Graph &graph,int s)
    :G(graph)
    {
        assert(s>=0 && s<G.V());
        visited=new bool[G.V()];
        from=new int[G.V()];
        for(int i=0;i<G.V();i++)
        {
            visited[i]=false;
            from[i]=-1;
        }
        this->s=s;
    }
    ~Path()
    {
        delete [] visited;
        delete [] from;
    }
    
    bool hasPath(int w)
    {
        return visited[w];
    }
    void Path(int w,vector<int> &vec)//得到某条路径方法为先用栈保存,然后存进vec中
    {
        stack<int> s;
        int p=w;
        while(p!=-1)
        {
            s.push(p);
            p=from[p];
        }
        
        vec.clear();
        while(!s.empty())
        {
            vec.push_back(s.top());
            s.pop();
        }
    }
    
    vois showPath(int w)
    {
        vector<int> vec;
        path(w,vec);
        for(int i=0;i<vec.size();i++)
        {
            cout<<vec[i];
            if(i==vec.size()-1)
                cout<<endl;
            else
                cout<<" ->  ";
        }
    }
;

#endif /* Path_h */


http://www.niftyadmin.cn/n/923634.html

相关文章

TCP是如何保证包的顺序传输?

我和大家一起讨论下TCP在保证可靠传输数据的前提下&#xff0c;是怎样对传输的数据进行顺序化操作的。 大家都知道&#xff0c;TCP提供了最可靠的数据传输&#xff0c;它给发送的每个数据包做顺序化&#xff08;这看起来非常烦琐&#xff09;&#xff0c;然而&#xff0c;如果…

UDP如何实现可靠传输

UDP不属于连接协议&#xff0c;具有资源消耗少&#xff0c;处理速度快的优点&#xff0c;所以通常音频&#xff0c;视频和普通数据在传送时&#xff0c;使用UDP较多&#xff0c;因为即使丢失少量的包&#xff0c;也不会对接受结果产生较大的影响。 传输层无法保证数据的可靠传…

端口号只有65535,如何做到百万并发量

每一个socketfd都对应一个五元组 &#xff08;remote ip&#xff0c;remote port&#xff0c;local ip&#xff0c;local port&#xff0c;proto&#xff09; 而65535只是local port的数量&#xff0c;其他的客户端的remote ip 和 remote port都有很多

剑指offer面试题3:数组中重复的数字

/*题目&#xff1a;找出数组中重复的数字 在一个长度为n的数组中所有的数字都是在0~n-1的范围内&#xff0c;数组中某些数字是重复的&#xff0c;但是不知道有几个数字重复了&#xff0c;也不知道每个数字重复了几次&#xff0c;请找出数组中任意一个重复的数字 例如&#xff1…

剑指offer面试题4:二维数组的查找

/* 题目&#xff1a;二维数组的查找在一个二位数组中&#xff0c;每一行都递增&#xff0c;每一列的递增&#xff0c;请完成一个函数&#xff0c;查找二维数组中是否有number*//*方案&#xff1a;只需要每次从二维数组的右上角开始查找就可以了&#xff0c;因为如果右上角的数字…

剑指offer面试题2.3.2字符串

/*因为str1和str2是在栈空间的两个不同的数组&#xff0c;所以它们的值不相同而str3和str4指向的都是常量字符串&#xff0c;它在内存中只有一份拷贝&#xff0c;因此str3和str4的值是一样的*/ #include <iostream> using namespace std;int main() {char str1[]"he…

TCP粘包、半包原理及解决方案

引言&#xff1a;TCP协议是网络通信协议中十分重要的协议&#xff0c;相比于UDP协议来说&#xff0c;它是一个可靠的传输协议&#xff0c;并且是一个面向数据流的协议&#xff1b;所谓面向数据流&#xff0c;其实是指数据传输是以流式的方式传输&#xff0c;这些传输的数据就像…