【数据结构】:图

本文介绍了图数据结构的基本概念,包括有向图与无向图、完全图、权重、邻接顶点、度、路径、连通图和强连通图等。此外,还探讨了图的两种存储方法——邻接矩阵和邻接表,并比较了它们的优缺点。最后,讨论了图的遍历策略,包括深度优先遍历和广度优先遍历。

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

  • 1、定义是一种非线性结构,由顶点的集合和顶点间的关系的集合组成的一种数据结构。
    Graph = (V,E);
    V = {x|x是顶点的集合};
    E = {<x,y> |(x,y属于V)};
  • 2、图的分类有向图:顶点之间单向指引就是有向图无向图:顶点之间可以互相指引就是无向图
    这里写图片描述
  • 3、一些基本概念
    1)完全图:在由n个顶点组成的无向图中,若有n(n-1)/2条边,则就是完全无向图
    2)权重:在一些图中,边具有与之相关的数值,称为权重。
    3)邻接顶点:如果(u,v)是图中的一条边,那么u,v互为邻接点。
    4)度:与顶点相关联的边的数目
    5)路径:一个顶点到另一个顶点所经过的痕迹
    6)连通图:在无向图中,任意两个顶点之间都是连通的。
    7)强连通图:在有向图中,若每一对顶点之间都存在路径,就称此图为强连通图。
    8)生成树:若一个图有n个顶点,则有n-1条边的就是生成树
    一个无向连通图的生成树是它的极小连通子图。
    -4、图的存储方法
    1)邻接矩阵
    A:如何存储:
    这里写图片描述
    B:代码如何实现:
template<class V,class W>
class GraphMatrix
{
public:
    //构造函数
    GraphMatrix(V* v,size_t n,bool isDirected = false,const W& invalue = W())
        :_v(v,v+n)
        ,_isDirected(isDirected)
    {
        _matrix = new W*[_v.size()];
        for(size_t i = 0; i<n; i++)
        {
            _matrix[i] = new W[_v.size()];
            for(size_t j = 0; j<n; j++)
            {
                _matrix[i][j] = invalue;
            }
        }
    }

    //给定一个顶点,如何得到这个顶点的下标
    size_t GetIndex(const V& v)
    {
        for(size_t i = 0; i<_v.size(); i++)
        {
            if(_v[i] == v)
            {
                return i;
            }
        }
        assert(false);
        return 0;
    }
    //如何加一条边
    void AddEge(const V& v1, const V& v2, const W& w)
    {
        size_t src = GetIndex(v1);
        size_t dest = GetIndex(v2);

        _matrix[src][dest] = w;
        if(_isDirected = false) //说明是无向图
        {
            _matrix[dest][src] = w;
        }
    }

    //析构函数
    ~GraphMatrix()
    {
        //先释放数据
        for(size_t i = 0; i<_v.size(); i++)
        {
            delete[] _matrix[i];
        }
        //后释放指针数组
        delete[] _matrix;
    }
private:
    vector<V> _v;     //顶点的集合
    W** _matrix;       //边上权重的集合
    bool _isDirected;  //是否是与有向图
};

2)邻接表
A:如何存储:
这里写图片描述
节点的设置:

template<class W>
struct GraphLinkNode
{
    W _weight;       //权重
    GraphLinkNode<W*> _next;  //下一个节点
    size_t _src;      
    size_t _dest;
    GraphLinkNode(size_t src,size_t dest,const W& weight = W())
        :_weight(weight)
        ,_next(NULL)
        ,_src(src)
        ,_dest(dest)
    {}
};

B:代码如何实现

template<class V, class W>
class GraphLink
{
    typedef LinKEdge<W> Edge;
public:

    GraphLink(V* vertexs, size_t n, const W& invalid = W(), bool isDirected = false)
        :_isDirected(isDirected)
    {
        _vertexs.resize(n);
        _vertexs.assign(vertexs, vertexs+n);

        _linkTables.resize(n, NULL);
    }
    size_t GetVertexIndex(const V& v)
    {
        for (size_t i = 0; i < _vertexs.size(); ++i)
        {
            if (_vertexs[i] == v)
            {
                return i;
            }
        }

        assert(false);
        return 0;
    }

    void _AddEdge(size_t src, size_t dst, const W& w)
    {
        // 头插
        LinKEdge<W>* edge = new Edge(src, dst, w);
        edge->_next = _linkTables[src];
        _linkTables[src] = edge;
    }

    void AddEdge(const V& v1, const V& v2, const W& w)
    {
        size_t src = GetVertexIndex(v1);
        size_t dst = GetVertexIndex(v2);

        _AddEdge(src, dst, w);
        if (_isDirected == false)
        {
            _AddEdge(dst, src, w);
        }
    }

protected:
    vector<V> _vertexs;  // 顶点集合
    vector<Edge*> _linkTables; // 邻接表
    bool _isDirected;
};

邻接矩阵和邻接表的比较及各自的用途:
说明:
A:就定义来说:
邻接矩阵更适合直接定位
邻接表适合搜寻相邻节点
B:存储
邻接矩阵:在无向图的存储中,邻接矩阵的存储方式是一种对称矩阵,这样的存储方式可以节省很大的内存空间
邻接表:在无向图的存储中,是要将重复的元素再次进行存储的,因此会有空间上的开销
C:找寻元素的相邻边
邻接矩阵:要按行,列,依次进行查找,时间复杂度很高
邻接表:直接就遍历依次指向此节点的链表即可
- 5、图的遍历
1)分类:
深度优先遍历
广度优先遍历
这里写图片描述
2)代码如何实现
A:深度优先遍历

void DFS(const V& src)
    {
        size_t index = GetVertexIndex(src);
        vector<bool> visited(_vertexs.size(),false);
        visited[index] = true;
        cout<<_vertexs[index]<<"->";
        _DFS(index,visited);

    }
    void _DFS(size_t src,vector<bool>& visited)
    {
        Edge* cur = _linkTables[src];
        while(cur)
        {
            size_t dst = cur->_dst;
            if(visited[dst] == false)
            {
                cout<<_vertexs[dst]<<"->"<<" ";
                visited[dst] = true;
                _DFS(dst,visited);
            }
            cur = cur->_next;
        }
    }

B:广度优先遍历

void BFS(const V& src)
    {
        size_t index = GetVertexIndex(src);
        vector<bool> visited(_vertexs.size(),false);
        queue<int> q;
        q.push(index);
        while(!q.empty())
        {
            size_t front = q.front();
            if(visited[front] == false)
            {
                cout<<_vertexs[front]<<"->";
                visited[front] = true;
                Edge* cur = _linkTables[front];
                while(cur)
                {
                    size_t dst = cur->_dst;
                    if(visited[dst] == false)
                    {
                        q.push(dst);
                        visited[dst] = true;
                        cout<<_vertexs[dst]<<"->";
                    }
                    cur = cur->_next;
                }
            }
            q.pop();
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值