namespace Graph
{
enum GraphKind { DG, DN, UDG, UDN };//图的种类,分别为有向图,有向网,无向图,无向网(带权图称为网)
class ALGraph
{
private:
struct ArcNode
{
int adjvex; //邻接顶点编号
ArcNode* nextArc; //对应顶点的下一条边
int weight;//边的权值
string info;//边的信息
explicit ArcNode(int adj, ArcNode* nexta = nullptr, int w = 1, const string& inf = string{}) :
adjvex(adj), nextArc(nexta), weight(w), info(inf) {}
};
struct Vnode//顶点表
{
string data;//顶点信息
ArcNode* firstArc; //指向顶点对应边表的第一个结点
};
static const int MAX_VERTEX_NUM = 1000; //图的最大顶点数
Vnode vertices[MAX_VERTEX_NUM]; //顶点表
int vexnum, arcnum; //分别为图的顶点数和边数
GraphKind kind; //图的种类
bool visited[MAX_VERTEX_NUM];
deque<int> que;
public:
explicit ALGraph(int vn = 0, int an = 0, GraphKind k = DG) : //初始化图,提供顶点数,边数和图的种类
vexnum(vn), arcnum(an), kind(k)
{
for (int i = 0; i < MAX_VERTEX_NUM; i++)//顶点表的指针结点初始化为nullptr
{
vertices[i].firstArc = nullptr;
}
}
~ALGraph()//析构函数
{
for (int i = 0; i < vexnum; i++) //删除每个顶点对应的边链表。
{
ArcNode* deleteArc, *p = vertices[i].firstArc;
while (p != nullptr)
{
deleteArc = p;
p = p->nextArc;
delete deleteArc;
}
}
}
const string& getVex(int n) //求编号为n的顶点的信息,如A/B/C编号为0,1, 2, 则编号为1的顶点返回B
{
if (n < 0 || n >= vexnum)
{
throw UnderflowException{};
}
return vertices[n].data;
}
int locateVex(const string& s)
{
int ret = -1;
for (int i = 0; i < vexnum; i++)
{
if (vertices[i].data == s)
{
ret = i;
break;
}
}
return ret;
}
void putVex(int n, const string& value)//修改顶点编号为n的值
{
if (n < 0 || n >= vexnum)
{
throw UnderflowException{};
}
vertices[n].data = value;
}
void insertVex(const string& s)//添加顶点
{
if (vexnum > MAX_VERTEX_NUM)
{
throw UnderflowException{};
}
vertices[vexnum++].data = s;
}
void deleteVex(const string& s) //删除顶点
{
int k = locateVex(s);
if (k < 0)
{
return;
}
for (int i = k + 1; i < vexnum; i++) //调整顶点表
{
vertices[i - 1] = vertices[i];
}
vexnum--;
ArcNode* pre = nullptr, * cur = nullptr, * deleteArc = nullptr;
for (int i = 0; i < vexnum; i++) //对于每个顶点的边表:删除边表中adjvex = k的边,如果边的adjvex > k,将其自减1
{
for (cur = vertices[i].firstArc; cur != nullptr;)
{
if (cur->adjvex == k)
{
deleteArc = cur;
cur = cur->nextArc;
if (cur == vertices[i].firstArc)
{
vertices[i].firstArc = cur;
}
else
{
pre->nextArc = cur;
}
delete deleteArc;
}
else
{
if (cur->adjvex > k)
{
cur->adjvex -= 1;
}
pre = cur;
cur = cur->nextArc;
}
}
}
}
void insertArc(const string& v1, const string& v2, int weight = 1, const string& inf = string{})
{
int n1 = locateVex(v1), n2 = locateVex(v2);
bool flag;
if (n1 >= 0 && n2 >= 0 && n1 != n2)
{
flag = true;
for (ArcNode* temp = vertices[n1].firstArc; temp != nullptr; temp = temp->nextArc)
{
if (temp->adjvex == n2)
{
flag = false;
break;
}
}
if (flag)
{
ArcNode* newArc = new ArcNode(n2, vertices[n1].firstArc, weight, inf);
vertices[n1].firstArc = newArc;
if (kind == UDG || kind == UDN)
{
ArcNode* copyArc = new ArcNode(n1, vertices[n2].firstArc, weight, inf);
vertices[n2].firstArc = copyArc;
}
arcnum++;
}
}
}
void deleteArc(const string& v1, const string& v2)
{
int n1 = locateVex(v1), n2 = locateVex(v2);
bool flag;
ArcNode* pre = nullptr, *cur = nullptr, *deleteArc = nullptr;
if (n1 >= 0 && n2 >= 0 && n1 != n2)
{
flag = false; //判断是否删除了边
cur = vertices[n1].firstArc;
while (cur != nullptr)
{
if (cur->adjvex == n2) //存在这条边
{
flag = true;
deleteArc = cur;
if (cur == vertices[n1].firstArc)
{
vertices[n1].firstArc = cur->nextArc;
}
else
{
pre->nextArc = cur->nextArc;
}
delete deleteArc;
if (kind == UDG || kind == UDN) //如果是无向图/网,则要额外删除一条边
{
cur = vertices[n2].firstArc;
while (cur != nullptr)
{
if (cur->adjvex == n1)
{
deleteArc = cur;
if (cur == vertices[n2].firstArc)
{
vertices[n2].firstArc = cur->nextArc;
}
else
{
pre->nextArc = cur->nextArc;
}
delete deleteArc;
}
else
{
pre = cur;
cur = cur->nextArc;
}
}
}
break;
}
else
{
pre = cur;
cur = cur->nextArc;
}
}
if (flag)
{
arcnum--;
}
}
}
void createGraph()
{
cout << "Enter vertex information:\n";
for (int i = 0; i < vexnum; i++)//输入顶点表信息,如A/B/C/D
{
cout << "vertex " << i << ": ";
getline(cin, vertices[i].data);
}
int containInfo;//用于判断是否要额外提供边的相关信息
cout << "Whether contain information in arcs(yes 1, no 0): ";
(cin >> containInfo).get();
switch (kind)
{
case DG: createDG(containInfo); break;
case DN: createDN(containInfo); break;
case UDG: createUDG(containInfo); break;
case UDN: createUDN(containInfo); break;
}
}
void createDG(int cInfo) //生成有向图
{
string v1, v2, arcInfo = "";
for (int i = 0; i < arcnum; )
{
cout << "enter arc " << i << " <v1,v2>\n";
cout << "v1: ";
getline(cin, v1);
cout << "v2: ";
getline(cin, v2);
int n1 = locateVex(v1), n2 = locateVex(v2);
bool flag; //判断需要添加的边是否已经在邻接表中
if (n1 != -1 && n2 != -1 && n1 != n2) //边有效
{
flag = true;
for (ArcNode* p = vertices[n1].firstArc; p != nullptr; p = p->nextArc) //确保输入的边不重复
{
if (p->adjvex == n2)
{
flag = false;
break;
}
}
if (flag)
{
i++;
if (cInfo)
{
cout << "info: ";
getline(cin, arcInfo);
}
ArcNode* newArc = new ArcNode(n2, vertices[n1].firstArc, 1, arcInfo);
vertices[n1].firstArc = newArc;
}
}
}
}
void createDN(int cInfo) //生成有向网
{
string v1, v2, arcInfo = "";
int weight;
for (int i = 0; i < arcnum; )
{
cout << "enter arc " << i << " <v1,v2> and its weight\n";
cout << "v1: ";
getline(cin, v1);
cout << "v2: ";
getline(cin, v2);
int n1 = locateVex(v1), n2 = locateVex(v2);
bool flag;
if (n1 != -1 && n2 != -1 && n1 != n2)
{
flag = true;
for (ArcNode* p = vertices[n1].firstArc; p != nullptr; p = p->nextArc) //确保输入的边不重复
{
if (p->adjvex == n2)
{
flag = false;
break;
}
}
if (flag)
{
i++;
cout << "weight: ";
(cin >> weight).get();
if (cInfo)
{
cout << "info: ";
getline(cin, arcInfo);
}
ArcNode* newArc = new ArcNode(n2, vertices[n1].firstArc, weight, arcInfo);
vertices[n1].firstArc = newArc;
}
}
}
}
void createUDG(int cInfo) //生成有向图
{
string v1, v2, arcInfo = "";
for (int i = 0; i < arcnum; )
{
cout << "enter arc " << i << " <v1,v2>\n";
cout << "v1: ";
getline(cin, v1);
cout << "v2: ";
getline(cin, v2);
int n1 = locateVex(v1), n2 = locateVex(v2);
bool flag;
if (n1 != -1 && n2 != -1 && n1 != n2) //边有效
{
flag = true;
for (ArcNode* p = vertices[n1].firstArc; p != nullptr; p = p->nextArc) //确保输入的边不重复
{
if (p->adjvex == n2)
{
flag = false;
break;
}
}
if (flag)
{
i++;
if (cInfo)
{
cout << "info: ";
getline(cin, arcInfo);
}
ArcNode* newArc1 = new ArcNode(n2, vertices[n1].firstArc, 1, arcInfo),
* newArc2 = new ArcNode(n1, vertices[n2].firstArc, 1, arcInfo);
vertices[n1].firstArc = newArc1;
vertices[n2].firstArc = newArc2;
}
}
}
}
void createUDN(int cInfo) //生成有向网
{
string v1, v2, arcInfo = "";
int weight;
for (int i = 0; i < arcnum; )
{
cout << "enter arc " << i << " <v1,v2> and its weight\n";
cout << "v1: ";
getline(cin, v1);
cout << "v2: ";
getline(cin, v2);
int n1 = locateVex(v1), n2 = locateVex(v2);
bool flag;
if (n1 != -1 && n2 != -1 && n1 != n2)
{
flag = true;
for (ArcNode* p = vertices[n1].firstArc; p != nullptr; p = p->nextArc) //确保输入的边不重复
{
if (p->adjvex == n2)
{
flag = false;
break;
}
}
if (flag)
{
i++;
cout << "weight: ";
(cin >> weight).get();
if (cInfo)
{
cout << "info: ";
getline(cin, arcInfo);
}
ArcNode* newArc1 = new ArcNode(n2, vertices[n1].firstArc, weight, arcInfo),
* newArc2 = new ArcNode(n1, vertices[n2].firstArc, weight, arcInfo);
vertices[n1].firstArc = newArc1;
vertices[n2].firstArc = newArc2;
}
}
}
}
const ArcNode* firstNeighbor(int v) const
{
if (v < 0 || v > arcnum)
{
throw UnderflowException{};
}
return vertices[v].firstArc;
}
void bfsTraverse()
{
cout << "\nBreadth first serach :\n";
for (int i = 0; i < vexnum; i++)
{
visited[i] = false;
}
que.clear();
for (int i = 0; i < vexnum; i++)
{
if (!visited[i])
{
BFS(i);
}
}
}
void BFS(int v)
{
visited[v] = true;
que.push_back(v);
while (!que.empty())
{
v = que.front();
que.pop_front();
cout << vertices[v].data << endl;
int w;
for (const ArcNode* temp = firstNeighbor(v); temp != nullptr; temp = temp->nextArc)
{
w = temp->adjvex;
if (!visited[w])
{
visited[w] = true;
que.push_back(w);
}
}
}
}
void dfsTraverse()
{
cout << "\nDepth first search:\n";
for (int i = 0; i < vexnum; i++)
{
visited[i] = false;
}
for (int i = 0; i < vexnum; i++)
{
if (!visited[i])
{
DFS(i);
}
}
}
void DFS(int v)
{
visited[v] = true;
cout << vertices[v].data << endl;
int w;
for (const ArcNode* temp = firstNeighbor(v); temp != nullptr; temp = temp->nextArc)
{
w = temp->adjvex;
if (!visited[w])
{
DFS(w);
}
}
}
void shortestPath_dij(const string& s0)
{
int v;
bool flag;//如果找不到最短距离时,退出查找最短路径的循环。
vector<int> dist(vexnum, INT_MAX); //记录最短距离
vector<int> path(vexnum); //用于记录最短路径
int v0 = locateVex(s0); //找到顶点对应的编号
if (v0 < 0) //顶点编号无效
{
throw UnderflowException{};
}
for (int i = 0; i < vexnum; i++) //集合S初始为空
{
visited[i] = false;
}
dist[v0] = 0; //v0到v0的距离为0,所以循环开始选择顶点v0
for (int i = 0; i < vexnum; i++)
{
flag = false;
int min = INT_MAX;
int w;
for (w = 0; w < vexnum; ++w)//选择源点通过集合S到集合V - S中每个的点最短路径Dk(k∈V-S)(简称最短距离集合)
{
if (!visited[w])//查找min{Dk|k∈V-S}
{
if (dist[w] < min)
{
v = w;
min = dist[w];
flag = true;
}
}
}
if (flag)//如果可以找到最小的Dk则继续循环
{
visited[v] = true; //假设最短路径为Dv,将v加入集合S
for (const ArcNode* temp = firstNeighbor(v); temp != nullptr; temp = temp->nextArc) //更新最短距离集合
{
w = temp->adjvex;
if (!visited[w] && (long(min) + temp->weight < dist[w]))
{
dist[w] = min + temp->weight;
path[w] = v;//记录边的另一个顶点。用于追溯到源点。
}
}
}
else
{
break;
}
}
vector<int> route; //用于记录最小距离的路径
for (int i = 0; i < vexnum; i++)//输出最短距离
{
if (i != v0)
{
cout << "\nshortest path from " << vertices[v0].data << " to " << vertices[i].data << ":\n";
cout << "Distance: ";
cout << dist[i] << endl;
cout << "Path: ";
if (dist[i] < INT_MAX) //假设有最短路径
{
route.clear();
int k = i;
while (k != v0)//追溯到v0
{
route.push_back(k);
k = path[k];
}
route.push_back(v0);
reverse(begin(route), end(route));//由于路径是反序排列,所以需要反转。
for (int j = 0; j < route.size(); j++)//打印路径
{
cout << vertices[route[j]].data << " ";
}
}
cout << endl;
}
}
}
};
}
图邻接表实现-C++
于 2022-07-01 11:24:10 首次发布