鄰接矩陣法中的殘留問題
template <int N, typename V, typename E> class MatrixGraph : public Graph<V, E> { protected: V *m_vertexes[N]; E *m_edges[N][N]; int m_eCount; public: // ... };
基本思想
爲了進一步提升空間使用率,能夠考慮使用鏈表替代數組,將鄰接矩陣換爲鄰接鏈表。ios
- 圖中的全部頂點按照編號存儲於統一個鏈表中
- 每個頂點對應一個鏈表,用於存儲始發於該頂點的邊
- 每一條邊的信息包含:起點,終點,權值
struct Edge : public Object { int b; // 起始頂點 int e; // 鄰接頂點 E data; // 權值 // ... };
struct Vertex : public Object { V *data; // 頂點數據元素值 LinkList<Edge> edge; // 鄰接於該頂點的邊 // ... }
int addVertex();編程
- 增長新的頂點,返回頂點編號
int addVertex(const V &value);數組
- 增長新頂點的同時附加數據元素
void removeVertex();安全
- 刪除最近增長的頂點
文件:Graph.hide
#ifndef GRAPH_H #define GRAPH_H #include "Object.h" #include "SharedPointer.h" #include "Array.h" namespace DTLib { template <typename E> struct Edge : public Object { int b; int e; E data; Edge(int i=-1, int j=-1) : b(i), e(j) { } Edge(int i, int j, const E &value) : b(i), e(j), data(value) { } bool operator == (const Edge &obj) { return (b == obj.b) && (e == obj.e); } bool operator != (const Edge &obj) { return !(*this == obj); } }; template <typename V, typename E> class Graph : public Object { public: virtual V getVertex(int i) const = 0; virtual bool getVertex(int i, V &value) const = 0; virtual bool setVertex(int i, const V &value) = 0; virtual SharedPointer<Array<int>> getAdjacent(int i) const = 0; virtual E getEdge(int i, int j) const = 0; virtual bool getEdge(int i, int j, E &value) const = 0; virtual bool setEdge(int i, int j, const E &value) = 0; virtual bool removeEdge(int i, int j) = 0; virtual int vCount() const = 0; virtual int eCount() = 0; virtual int OD(int i) = 0; virtual int ID(int i) = 0; virtual int TD(int i) { return OD(i) + ID(i); } }; } #endif // GRAPH_H
文件:ListGraph.hthis
#ifndef LISTGRAPH_H #define LISTGRAPH_H #include "Graph.h" #include "Exception.h" #include "LinkList.h" #include "DynamicArray.h" namespace DTLib { template <typename V, typename E> class ListGraph : public Graph<V, E> { public: ListGraph(unsigned int n = 0) { for (unsigned int i=0; i<n; ++i) { addVertex(); } } int addVertex() { int ret = -1; Vertex *v = new Vertex(); if (v != nullptr) { m_list.insert(v); ret = m_list.length() - 1; } else { THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create vertex object ..."); } return ret; } int addVertex(const V &value) { int ret = addVertex(); if (ret >= 0) { setVertex(ret, value); } return ret; } void removeVertex() { if (m_list.length() > 0) { int index = m_list.length() - 1; Vertex *v = m_list.get(index); if (m_list.remove(index)) { for (int i=(m_list.move(0), 0); !m_list.end(); ++i, m_list.next()) { int pos = m_list.current()->edge.find(Edge<E>(i, index)); if (pos >= 0) { m_list.current()->edge.remove(pos); } } delete v->data; delete v; } else { THROW_EXCEPTION(InvalidOpertionExcetion, "No vertex in current graph ..."); } } } V getVertex(int i) const override { V ret; if (!getVertex(i, ret)) { THROW_EXCEPTION(InvalidParameterExcetion, "Parameter i is invalid ..."); } return ret; } bool getVertex(int i, V &value) const override { bool ret = (0 <= i) && (i < vCount()); if (ret) { Vertex *v = m_list.get(i); if (v->data != nullptr) { value = *(v->data); } else { THROW_EXCEPTION(InvalidOpertionExcetion, "No value assigned to this vertex ..."); } } return ret; } bool setVertex(int i, const V &value) override { bool ret = (0 <= i) && (i < vCount()); if (ret) { Vertex *v = m_list.get(i); V *data = v->data; if (data == nullptr) { data = new V(); } if (data != nullptr) { *data = value; v->data = data; // 異常安全!!! } else { THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create new vertex object ..."); } } return ret; } SharedPointer<Array<int>> getAdjacent(int i) const override { DynamicArray<int> *ret = nullptr; if ((0 <= i) && (i < vCount())) { Vertex *v = m_list.get(i); ret = new DynamicArray<int>(v->edge.length()); if (ret != nullptr) { for (int j=(v->edge.move(0), 0); !v->edge.end(); ++j, v->edge.next()) { ret->set(j, v->edge.current().e); } } else { THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create ret object ..."); } } else { THROW_EXCEPTION(InvalidParameterExcetion, "Parameter i is invalid ..."); } return ret; } E getEdge(int i, int j) const override { E ret; if (!getEdge(i, j, ret)) { THROW_EXCEPTION(InvalidParameterExcetion, "Parameter <i, j> is invalid ..."); } return ret; } bool getEdge(int i, int j, E &value) const override { bool ret = ((0 <= i) && (i < vCount())) && ((0 <= j) && (j < vCount())); if (ret) { Vertex *v = m_list.get(i); int pos = v->edge.find(Edge<E>(i, j)); if (pos >= 0) { value = v->edge.get(pos).data; } } else { THROW_EXCEPTION(NoEnoughMemoryException, "No value assigned to this ret edge ..."); } return ret; } bool setEdge(int i, int j, const E &value) override { bool ret = ((0 <= i) && (i < vCount())) && ((0 <= j) && (j < vCount())); if (ret) { Vertex *v = m_list.get(i); int pos = v->edge.find(Edge<E>(i, j)); if (pos >= 0) { ret = v->edge.set(pos, Edge<E>(i, j, value)); } else { ret = v->edge.insert(0, Edge<E>(i, j, value)); } } return ret; } bool removeEdge(int i, int j) override { bool ret = ((0 <= i) && (i < vCount())) && ((0 <= j) && (j < vCount())); if (ret) { Vertex *v = m_list.get(i); int pos = v->edge.find(Edge<E>(i, j)); if (pos >= 0) { ret = v->edge.remove(pos); } } return ret; } int vCount() const override { return m_list.length(); } int eCount() override { int ret = 0; for (m_list.move(0); !m_list.end(); m_list.next()) { ret += m_list.current()->edge.length(); } return ret; } int OD(int i) override { int ret = 0; if ((0 <= i) && (i < vCount())) { ret = m_list.get(i)->edge.length(); } else { THROW_EXCEPTION(InvalidParameterExcetion, "Parameter i is valid ..."); } return ret; } int ID(int i) override { int ret = 0; if ((0 <= i) && (i < vCount())) { for (m_list.move(0); !m_list.end(); m_list.next()) { LinkList<Edge<E>> &edge = m_list.current()->edge; for (edge.move(0); !edge.end(); edge.next()) { if (edge.current().e == i) { ++ret; break; } } } } else { THROW_EXCEPTION(InvalidParameterExcetion, "Parameter i is invalid ..."); } return ret; } ~ListGraph() { while (m_list.length() > 0) { Vertex *toDel = m_list.get(0); m_list.remove(0); delete toDel->data; delete toDel; } } protected: struct Vertex : public Object { V *data = nullptr; LinkList<Edge<E>> edge; }; LinkList<Vertex*> m_list; ListGraph(const ListGraph<V, E> &) = default; ListGraph &operator = (const ListGraph<V, E> &) = default; }; } #endif // LISTGRAPH_H
文件:main.cppspa
#include <iostream> #include "ListGraph.h" using namespace std; using namespace DTLib; int main() { ListGraph<char, int> g(4); g.setVertex(0, 'A'); g.setVertex(1, 'B'); g.setVertex(2, 'C'); g.setVertex(3, 'D'); for (int i=0; i<g.vCount(); ++i) { cout << i << " : " << g.getVertex(i) << endl; } cout << "--------" << endl; g.removeVertex(); g.removeVertex(); for (int i=0; i<g.vCount(); ++i) { cout << i << " : " << g.getVertex(i) << endl; } cout << "--------" << endl; g.addVertex('C'); g.addVertex('D'); for (int i=0; i<g.vCount(); ++i) { cout << i << " : " << g.getVertex(i) << endl; } cout << "--------" << endl; g.setEdge(0, 1, 5); g.setEdge(0, 3, 6); g.setEdge(1, 2, 8); g.setEdge(2, 3, 2); g.setEdge(3, 1, 9); cout << "W(0, 1) : " << g.getEdge(0, 1) << endl; cout << "W(0, 3) : " << g.getEdge(0, 3) << endl; cout << "W(1, 2) : " << g.getEdge(1, 2) << endl; cout << "W(2, 3) : " << g.getEdge(2, 3) << endl; cout << "W(3, 1) : " << g.getEdge(3, 1) << endl; cout << "--------" << endl; cout << "vCount : " << g.vCount() << endl; cout << "eCount : " << g.eCount() << endl; cout << "--------" << endl; SharedPointer<Array<int>> aj = g.getAdjacent(0); for (int i=0; i<aj->length(); ++i) { cout << (*aj)[i] << " "; } cout << endl; cout << "--------" << endl; cout << "ID(1) : " << g.ID(1) << endl; cout << "OD(1) : " << g.OD(1) << endl; cout << "TD(1) : " << g.TD(1) << endl; cout << "--------" << endl; g.removeVertex(); cout << "vCount : " << g.vCount() << endl; cout << "eCount : " << g.eCount() << endl; return 0; };
輸出:設計
0 : A 1 : B 2 : C 3 : D -------- 0 : A 1 : B -------- 0 : A 1 : B 2 : C 3 : D -------- W(0, 1) : 5 W(0, 3) : 6 W(1, 2) : 8 W(2, 3) : 2 W(3, 1) : 9 -------- vCount : 4 eCount : 5 -------- 3 1 -------- ID(1) : 2 OD(1) : 1 TD(1) : 3 -------- vCount : 3 eCount : 2
- 鄰接鏈表法使用鏈表對圖相關的數據進行存儲
- 每個頂點關聯一個鏈表,用於存儲相關的數據
- 全部頂點按照編號被組織在同一個鏈表中
- 鄰接鏈表法實現的圖可以支持動態添加/刪除頂點
以上內容整理於狄泰軟件學院系列課程,請你們保護原創!3d