问题描述
目的:使用C++模板设计并逐步完善图的邻接表抽象数据类型(ADT)。
内容:(1)请参照图的邻接矩阵模板类原型,设计并逐步完善图的邻接表ADT。(由于该环境目前仅支持单文件的编译,故将所有内容都集中在一个源文件内。在实际的设计中,推荐将抽象类及对应的派生类分别放在单独的头文件中。)
(2)设计并实现一个算法,在已存在的有权图中取两端点为u和v的边上的权值。获取成功,返回true;否则返回false。图的存储结构采用邻接表。将其加入到ADT中。
注意:DG(有向图), DN(有向网), UDG(无向图), UDN(无向网)
参考函数原型:
//对于有权图,取两端点为v1和v2的边上的权值。获取成功,返回true;否则,返回false
template<class TypeOfVer, class TypeOfEdge>
bool adjlist_graph<TypeOfVer, TypeOfEdge>::GetWeight(int u, int v, int &w);
图的邻接表模板类原型参考如下:
/* 边表的结点定义 */
template<class TypeOfEdge>
struct edgeNode
{
int data;
TypeOfEdge weight;
edgeNode<TypeOfEdge> *next;
edgeNode(const int &d, edgeNode<TypeOfEdge> *ptr = NULL) //构造函数,用于构造其他结点(无权图)
//函数参数表中的形参允许有默认值,但是带默认值的参数需要放后面
{
next = ptr;
data = d;
}
edgeNode(const int &d, const TypeOfEdge &w, edgeNode<TypeOfEdge> *ptr = NULL) //构造函数,用于构造其他结点(带权图)
//函数参数表中的形参允许有默认值,但是带默认值的参数需要放后面
{
next = ptr;
data = d;
weight = w;
}
int getData(){ return data;} //取得结点的序号(顶点集)
TypeOfEdge getWeight(){ return weight;} //取得边集中对应边的权值
void SetLink( edgeNode<TypeOfEdge> *link ){ next = link; } //修改结点的next域
void SetData( int value ){ data = value; } //修改结点的序号(顶点集)
void SetWeight(TypeOfEdge value ){ weight = value; } //修改边集中对应边的权值
};
//图的邻接表类
template<class TypeOfVer, class TypeOfEdge>
struct verNode
{
TypeOfVer ver;
edgeNode<TypeOfEdge> *head;
verNode(edgeNode<TypeOfEdge> *h = NULL){head = h;}
TypeOfVer getVer(){ return ver;} //取得结点值(顶点集)
edgeNode<TypeOfEdge> *getHead(){ return head;} //取得对应的边表的头指针
void setVer(TypeOfVer value){ ver = value;} //设置结点值(顶点集)
void setHead(edgeNode<TypeOfEdge> *value){ head = value;} //设置对应的边表的头指针
};
template <class TypeOfVer, class TypeOfEdge>
class adjlist_graph{
private:
int Vers; //顶点数
int Edges; //边数
verNode<TypeOfVer,TypeOfEdge> *verList;
string GraphKind; //图的种类标志
bool Delete_Edge( int u, int v );
bool DFS(int u, int &num, int visited[]); //DFS遍历(递归部分)
public:
adjlist_graph( const string &kd, int vSize, const TypeOfVer d[]); //构造函数构造一个只有结点没有边的图。
adjlist_graph( const string &kd, int vSize, int eSize, const TypeOfVer d[], int **e); 构造函数构造一个无权图。5个参数的含义:图的类型、结点数、边数、结点集和边集
adjlist_graph( const string &kd, int vSize, int eSize, const TypeOfVer d[], int **e, const TypeOfEdge w[]); //构造函数构造一个有权图。
bool GraphisEmpty() { return Vers == 0; } //判断图空否
string GetGraphKind(){ return GraphKind; }
bool GetVer(int u, TypeOfVer &data); //取得G中指定顶点的值
int GetFirstAdjVex(int u, int &v); //返回G中指定顶点u的第一个邻接顶点的位序(顶点集)。若顶点在G中没有邻接顶点,则返回-1
int GetNextAdjVex(int u, int v, int &w); //返回G中指定顶点u的下一个邻接顶点(相对于v)的位序(顶点集)。若顶点在G中没有邻接顶点,则返回false
bool PutVer(int u, TypeOfVer data); //对G中指定顶点赋值
bool InsertVer(const TypeOfVer &data); //往G中添加一个顶点
int LocateVer(TypeOfVer data); //返回G中指定顶点的位置
bool ExistEdge(int u, int v);
bool PrintVer(); //输出顶点集
bool PrintAdjList(); //输出邻接矩阵
int GetVerNum(){ return Vers;} //取得当前顶点数
int GetEdgeNum(){ return Edges;} //取得当前边数
bool Insert_Edge(int u, int v); //无权图插入一条边
bool Insert_Edge(int u, int v, TypeOfEdge w); //有权图插入一条边
bool DeleteVer(const TypeOfVer &data); //往G中删除一个顶点
bool DeleteEdge( int u, int v ); //删除边 (外壳:有向(删除1条边), 无向(删除2条边))
void DFS_Traverse(int u); //DFS遍历(外壳部分)
void BFS_Traverse(int u); //BFS遍历
~adjlist_graph(); //析构函数
};
输入说明
建图的输入数据格式参见建图的算法说明。
第一行:图的类型
第二行:结点数
第三行:结点集
第四行:边数
第五行:边集
第六行:权集
第六行:邻接顶点1
第七行:邻接顶点2
输出说明
第一行:顶点集
第二行:邻接表
空行
第三行:true(false)
第四行:权值(true的情况)
#include <iostream>
#include <string>
using namespace std;
template<class TypeOfEdge>
struct edgeNode
{
int data;
TypeOfEdge weight;
edgeNode<TypeOfEdge> *next;
edgeNode(const int &d, const TypeOfEdge &w, edgeNode<TypeOfEdge> *ptr = nullptr)
{
data = d;
weight = w;
next = ptr;
}
};
template<class TypeOfVer, class TypeOfEdge>
struct verNode
{
TypeOfVer ver;
edgeNode<TypeOfEdge> *head;
verNode(edgeNode<TypeOfEdge> *h = nullptr)
{
head = h;
}
};
template <class TypeOfVer, class TypeOfEdge>
class adjlist_graph
{
private:
int Vers; // Number of vertices
verNode<TypeOfVer,TypeOfEdge> *verList;
string GraphKind;
public:
adjlist_graph(const string &kd, int vSize, const TypeOfVer d[]) : Vers(vSize), GraphKind(kd)
{
verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
for (int i = 0; i < Vers; ++i)
{
verList[i].ver = d[i];
}
}
adjlist_graph(const string &kd, int vSize, int eSize, const TypeOfVer d[], int **e) : Vers(vSize), GraphKind(kd)
{
verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
for (int i = 0; i < Vers; ++i)
{
verList[i].ver = d[i];
verList[i].head = nullptr;
}
for (int i = 0; i < eSize; ++i)
{
int u = e[i][0];
int v = e[i][1];
edgeNode<TypeOfEdge> *newNode = new edgeNode<TypeOfEdge>(v, 0, verList[u].head);
verList[u].head = newNode;
newNode = new edgeNode<TypeOfEdge>(u, 0, verList[v].head);
verList[v].head = newNode;
}
}
adjlist_graph(const string &kd, int vSize, int eSize, const TypeOfVer d[], int **e, const TypeOfEdge w[]) : Vers(vSize), GraphKind(kd)
{
verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
for (int i = 0; i < Vers; ++i)
{
verList[i].ver = d[i];
verList[i].head = nullptr;
}
for (int k = 0; k < eSize; ++k)
{
int u = e[k][0];
int v = e[k][1];
TypeOfEdge weight = w[k];
// 根据图的类型来区分有权图和无权图
if (GraphKind == "DG" || GraphKind == "DN")
{
// 有向图或有向网
edgeNode<TypeOfEdge> *newNode = new edgeNode<TypeOfEdge>(v, weight, verList[u].head);
verList[u].head = newNode;
}
else
{
// 无向图或无向网,需要添加两条边
edgeNode<TypeOfEdge> *newNode = new edgeNode<TypeOfEdge>(v, weight, verList[u].head);
verList[u].head = newNode;
newNode = new edgeNode<TypeOfEdge>(u, weight, verList[v].head);
verList[v].head = newNode;
}
}
}
~adjlist_graph()
{
for (int i = 0; i < Vers; ++i)
{
edgeNode<TypeOfEdge> *curr = verList[i].head;
while (curr != nullptr)
{
edgeNode<TypeOfEdge> *temp = curr;
curr = curr->next;
delete temp;
}
}
delete[] verList;
}
void printAdjList()
{
for (int i = 0; i < Vers; ++i)
{
cout << verList[i].ver;
edgeNode<TypeOfEdge> *curr = verList[i].head;
while (curr != nullptr)
{
cout << "->" << curr->data << "(" << curr->weight << ")";
curr = curr->next;
}
cout << "->nullptr" << endl;
}
}
bool PrintMatrix()
{
cout << GraphKind << endl;
for (int i = 0; i < Vers; ++i)
{
cout << verList[i].ver;
if (i != Vers - 1)
cout << " ";
}
cout<<endl;
return true;
}
bool GetWeight(int u, int v, TypeOfEdge &w);
};
template<class TypeOfVer, class TypeOfEdge>
bool adjlist_graph<TypeOfVer, TypeOfEdge>::GetWeight(int u, int v, TypeOfEdge &w)
{
// 首先检查顶点是否有效
if (u < 0 || u >= Vers || v < 0 || v >= Vers)
return false;
// 遍历顶点 u 的邻接表
edgeNode<TypeOfEdge> *curr = verList[u].head;
while (curr != nullptr)
{
if (curr->data == v)
{
w = curr->weight; // 找到边,将权值赋给 w
return true;
}
curr = curr->next;
}
return false; // 没有找到与顶点 v 相连接的边
}
int main()
{
string graphType;
int n, m;
cin >> graphType >> n;
char *verArr = new char[n];
for (int i = 0; i < n; ++i)
{
cin >> verArr[i];
}
cin >> m;
int **edgeArr = new int*[m];
for (int i = 0; i < m; ++i)
{
edgeArr[i] = new int[2];
cin >> edgeArr[i][0] >> edgeArr[i][1];
}
int *weightArr = new int[m];
for (int i = 0; i < m; ++i)
{
cin >> weightArr[i];
}
int u, v;
cin >> u >> v;
adjlist_graph<char, int> graph(graphType, n, m, verArr, edgeArr, weightArr);
// 输出顶点集和邻接表
for (int i = 0; i < n; ++i)
{
cout << verArr[i];
if(i<n-1)cout<<" ";
}
cout<<endl<<n;
cout << endl;
graph.printAdjList();
cout << endl;
// 获取边的权值
int weight;
bool success = graph.GetWeight(u, v, weight);
// 输出结果
if (success)
{
cout << "true" << endl;
cout << weight << endl;
}
else
{
cout << "false" << endl;
}
// 释放动态内存
delete[] verArr;
for (int i = 0; i < m; ++i)
{
delete[] edgeArr[i];
}
delete[] edgeArr;
delete[] weightArr;
return 0;
}