本文記錄了基於鄰接表表示的有向有權圖的基本操作。鄰接表表示的圖的結構就是用一個散列表存儲圖的節點,而每個節點後面跟着從節點出發的所有邊的集合,這些邊用鏈表連接起來,所以在這樣的圖中尋找一個節點發出的邊是容易的,但是尋找進入一個節點的邊是困難的,需要遍歷所有的邊。刪除一條邊也比較容易,刪除一個節點則需要尋找與該節點相關的所有邊,並將這些邊也刪除。
#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
這些數據結構都是爲後面的算法準備的,所以就不貼測試代碼,就我目前已經完成的算法來看,這些基本操作沒有出錯。