每日一題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

這些數據結構都是爲後面的算法準備的,所以就不貼測試代碼,就我目前已經完成的算法來看,這些基本操作沒有出錯。

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