每日一题28:图的基本操作

本文记录了基于邻接表表示的有向有权图的基本操作。邻接表表示的图的结构就是用一个散列表存储图的节点,而每个节点后面跟着从节点出发的所有边的集合,这些边用链表连接起来,所以在这样的图中寻找一个节点发出的边是容易的,但是寻找进入一个节点的边是困难的,需要遍历所有的边。删除一条边也比较容易,删除一个节点则需要寻找与该节点相关的所有边,并将这些边也删除。

#ifndef _NOWEIGHTGRAPH_H_
#define _NOWEIGHTGRAPH_H_
#include "../include/Vector.h"

namespace MyDataStructure
{
    template<typename Value, typename Edge>
    struct Vertice
    {
        typedef Value ValueType;
        typedef Edge* EdgePtr;
        typedef Edge EdgeType;
        ValueType value;
        EdgeType* adj;
    };

    template<typename Weight>
    struct Edge
    {
        typedef Weight WeightType;
        typedef typename Edge<WeightType> EdgeType;
        typedef EdgeType* EdgePtr;
        int src;
        int dst;
        WeightType weight;
        EdgeType* next;
    };


    template<typename Value, typename Weight>
    class DirectedWeightGraph
    {
    public:
        typedef Value ValueType;
        typedef Weight WeightType;
        typedef typename Vertice<ValueType, Edge<WeightType>> VerticeType;
        typedef typename Edge<WeightType> EdgeType;
        typedef VerticeType* VerticePtr;
        typedef EdgeType* EdgePtr;
        typedef DirectedWeightGraph<ValueType, WeightType> self;

    public:
        DirectedWeightGraph(){}
        DirectedWeightGraph(ValueType values[], int vertice_count,
            int src[], int dst[], WeightType weight[], int edge_count)
        {
            for (int i = 0; i < vertice_count; ++i)
            {
                AddVertice(values[i]);
            }
            for (int i = 0; i < edge_count; ++i)
            {
                AddEdge(src[i], dst[i], weight[i]);
            }
        }
        DirectedWeightGraph(const Vector<ValueType>& values,
            const Vector<int>& src,const Vector<int>& dst,
            const Vector<WeightType>& weight)
        {
            int vertice_count = values.Size();
            for (int i = 0; i < vertice_count; ++i)
            {
                AddVertice(values[i]);
            }
            int edge_count = weight.Size();
            for (int i = 0; i < edge_count; ++i)
            {
                AddEdge(src[i], dst[i], weight[i]);
            }
        }
        ~DirectedWeightGraph(){}
        VerticePtr CreateVertice(ValueType value)
        {
            VerticeType* vertice = new VerticeType;
            vertice->value = value;
            vertice->adj = nullptr;
            return vertice;
        }
        EdgePtr CreateEdge(int src, int dst, WeightType weight)
        {
            EdgeType* edge = new EdgeType;
            edge->src = src;
            edge->dst = dst;
            edge->next = nullptr;
            edge->weight = weight;
            return edge;
        }
        int AddVertice(ValueType value)
        {
            VerticePtr v = CreateVertice(value);
            return AddVertice(v);
        }
        int AddVertice(VerticePtr vertice)
        {
            int size = Vertices.Size();
            int i = 0;
            while (i < size)
            {
                if (Vertices[i] == nullptr)
                {
                    Vertices[i] = vertice;
                    break;
                }
                ++i;
            }
            if (i >= size)
            {
                Vertices.PushBack(vertice);
            }
            ++VerticeCount;
            return i;
        }
        bool IsVerticeContianed(int v) const
        {
            if (v < 0 || v >= Vertices.Size()) return false;
            //有些节点是哑的,这样的节点占用空间,但实际上是不存在的
            return Vertices[v] != nullptr;
        }

        bool IsVerticeContianed(VerticePtr v) const
        {
            if (v == nullptr) return false;
            int size = Vertices.Size();
            for (int i = 0; i < size; ++i)
            {
                if (Vertices[i] == v) return true;
            }
            return false;
        }

        //允许两个顶点间有多条路径,这些不同路径也可以具有同样的权值
        bool AddEdge(int src, int dst, WeightType weight)
        {
            if (IsVerticeContianed(src) && IsVerticeContianed(dst) && src != dst)
            {
                EdgeType* e = Vertices[src]->adj;
                Vertices[src]->adj = CreateEdge(src, dst, weight);
                Vertices[src]->adj->next = e;
                ++EdgeCount;
                return true;
            }
            return false;
        }
        bool IsConnected(int src, int dst) const 
        {
            if (src == dst) return true;
            if (IsVerticeContianed(src) && IsVerticeContianed(dst))
            {
                EdgePtr e = Vertices[src].adj;
                while (e != nullptr)
                {
                    if (e->dst == dst) return true;
                }
            }
            return false;
        }
        bool GetVerticeValue(int v, ValueType& value) const 
        {
            if (IsVerticeContianed(v))
            {
                value = Vertices[v]->value;
                return true;
            }
            return false;
        }
        bool GetWeight(int src, int dst, WeightType& weight) const 
        {

            if (IsVerticeContianed(src) && IsVerticeContianed(dst))
            {
                if (src == dst)
                {
                    weight = 0;
                    return true;
                }
                EdgePtr e = Vertices[src]->adj;
                while (e != nullptr)
                {
                    if (e->dst == dst)
                    {
                        weight = e->weight;
                        return true;
                    }
                    e = e->next;
                }
            }
            return false;
        }
        void RemoveVertice(int v)
        {
            if (IsVerticeContianed(v))
            {
                int size = Vertices.Size();
                EdgePtr e = Vertices[v].adj;
                //移除从待删除节点出发的边
                while (e != nullptr)
                {
                    EdgePtr temp = e->next;
                    delete e;
                    --EdgeCount;
                    e = temp;
                }
                //删除节点,但是这个位置不能丢弃,
                //让它存放一个表示哑节点的空指针
                delete Vertices[v];
                Vertices[v] = nullptr;
                //移除进入删除节点的边
                for (int i = 0; i < size; ++i)
                {
                    if (Vertices[i] != nullptr)
                        remove_edge(i, v);
                }
            }
        }
        void RemoveEdge(int src, int dst)
        {
            if (IsVerticeContianed(src) && IsVerticeContianed(dst))
            {
                remove_edge(src, dst);
            }
        }
        //返回实际存储的节点个数
        int GetVerticeCount() const { return VerticeCount; }
        //返回实际存储的边的个数
        int GetEdgeCount() const { return EdgeCount; }
        //返回为保存节点已经占用的空间,有的空间被占用了,
        //但实际上存放的是哑节点
        int GetVerticeSize() const
        {
            return Vertices.Size();
        }
        VerticePtr GetVertice(int v) const
        {
            if (v < 0 || v >= Vertices.Size()) return nullptr;
            return Vertices[v];
        }
    private:
        void remove_edge(int src, int dst)
        {
            if (src == dst) return;
            EdgePtr e = Vertices[src]->adj;
            EdgePtr pre;
            while (e != nullptr)
            {
                pre = e;
                if (e->dst == dst)
                {
                    if (e == Vertices[src]->adj)
                    {
                        Vertices[src]->adj = e->next;
                        delete pre;
                        e = Vertices[src]->adj;
                    }
                    else
                    {
                        pre->next = e->next;
                        delete e;
                        e = pre->next;
                    }
                    --EdgeCount;
                }
                else e = e->next;
            }
        }
    private:
        int VerticeCount;
        int EdgeCount;
        Vector<VerticePtr> Vertices;
    };
}
#endif

这些数据结构都是为后面的算法准备的,所以就不贴测试代码,就我目前已经完成的算法来看,这些基本操作没有出错。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章