广州大学学生实验报告
开课实验室:计算机科学与工程实验(电子楼417) 2018年05月31日
学院 |
计算机科学与教育软件学院 |
年级、专业、班 |
网络161 |
姓名 |
卟咚君 |
学号 |
1606100*** |
|
实验课程名称 |
数据结构实验 |
成绩 |
|
|||||
实验项目名称 |
实验三:图的遍历生成树 |
指导老师 |
** |
|||||
一、实验目的 1、把图转化为程序能识别的邻接矩阵; 2、理解图的遍历方法及对应的生成树。 二、使用仪器、器材 微机一台 操作系统:WinXP 编程软件:C++ 三、实验内容及原理 实验内容: 图的输入:邻接矩阵直接写入源程序,或键盘输入,或读入数据文件 起始结点的输入:运行时由键盘输入 输出:生成树的边,用结点的序偶表示,例如 (1,3) 思路:定义一个class类Edge为图的边 定义一个class类Vertex为图的点 定义一个class类Graph为图 图的顶点个数和邻接矩阵由键盘输入,在图中存储了图的邻接矩阵,另外图中的每一个结点都有相应的data值和一个链首,链表存储的是这个顶点的连边,边上有相应的边权和目标点。插入一个新的结点的data值,插入一条新的连边,修改和撤销原本存在的连边,按照树的序偶表示的方式输出图的连边和输出图的邻接矩阵,以及深度和广度优先遍历生成一棵树(或者森林)的操作基本是在点和点的边的链表之间的操作。在 按照树的序偶表示的方式输出图的连边时,由于可能一条边遍历的时候会输出两次,需要标记已经输出的边,防止重复。在输出图的邻接矩阵时,由于在上述的操作中,基本是对点和点的边链表进行操作的,需要按照目前链表的信息更新图的邻接矩阵的信息,再输出。在深度优先生成一棵树(或者森林)输出的时候,由于可能是不连通图,先把键盘输入的起始点的深度优先遍历的图输出(void DFSprint(int s)),标记输出的点,然后遍历图中所有的点,查找没有遍历过的点,再对它进行深度优先遍历(函数void DFS(int s) ),再标记输出的点,重复这个操作,直到所有的点输出。在广度优先生成一棵树(或者森林)时,由于可能是不连通图,先把键盘输入的起始点的广度优先遍历的图输出(void DFSprint(int s)),标记输出的点,然后遍历图中所有的点,查找没有遍历过的点,再对它进行广度优先遍历(函数void DFS(int s) ),再标记输出的点,重复这个操作,直到所有的点输出。 #include using namespace std; template<typename DistType> class Edge { public: Edge(int dest, DistType cost) : dest(dest), cost(cost), next(NULL) {}
public: int dest; DistType cost; Edge<DistType> *next;
}; template<typename NameType, typename DistType> class Vertex { public: Vertex() : adj(NULL) {} NameType data; Edge<DistType> *adj; ~Vertex(); }; template<typename NameType, typename DistType> Vertex<NameType, DistType>::~Vertex() { Edge<DistType> *pmove = adj; while (pmove) { adj = pmove->next; delete pmove; pmove = adj; } } template<typename NameType, typename DistType> class Graph { public: Graph(int size = DefaultSize); //建立一个有size个结点的图 ~Graph(); bool GraphEmpty() const { //判断图是否为空图 return 0 == numvertex; } bool GraphFull() const { //判断图是否已满 return MaxNum == numvertex; } int NumberOfVertex() const { //返回图中结点的个数 return numvertex; } int NumberOfEdge() const { //返回图中的边的个数 return numedges; } void intputGraph(DistType maps[][100]); NameType GetValue(int u); //返回图中结点v的data DistType GetWeight(int u, int v); //返回结点u和结点v之间的连边的边权 bool InsertVertex(int u, const NameType Data); //在结点u插入新的Data值 bool Removevertex(int u); //移除结点u bool InsertEdge(int v1, int v2, DistType weight = Infinity); //在结点u和结点v之间插入边Cost bool RemoveEdge(int v1, int v2); //移除u和v之间的连边 void Print(); //输出图 void Print2(); //输出图 int Getvertexpos(const NameType Data); //返回结点data==vertex的结点序号 void DFSprint(int s); //深度优先生成一棵树(或者森林) void DFS(int s); //深度优先生成一棵树 void BFSprint(int s); //广度优先生成一棵树(或者森林) void BFS(int s); //广度优先生成一棵树 private: Vertex<NameType, DistType> *nodetable; //图的结点,用链表的方式存储 int numvertex; //图中结点的总数 const int MaxNum; //图中最大能存储的结点总数 static const int DefaultSize = 10; //默认情况下图的最大能存储的结点总数 static const DistType Infinity = -1; //当边权==Infinity == -1时,默认为边权无穷大,对应的两点之间没有边相连 int numedges; //图中的边数 bool *flag; //标记数组 DistType map[100][100]; //图的邻接矩阵 }; template<typename NameType, typename DistType> Graph<NameType, DistType>::Graph(int size) //建立一个有size个结点的图 : numvertex(0), MaxNum(size), numedges(0) { nodetable = new Vertex<NameType, DistType>[size]; flag = new bool[size]; for (int i = 0; i < MaxNum; i++) nodetable[i].data = NULL; } template<typename NameType, typename DistType> Graph<NameType, DistType>::~Graph() { //撤销图,将图中申请的结点和边的释放 Edge<DistType> *pmove; for (int i = 0; i<this->numvertex; i++) { pmove = this->nodetable[i].adj; if (pmove) { this->nodetable[i].adj = pmove->next; delete pmove; pmove = this->nodetable[i].adj; } } delete[] nodetable; } template<typename NameType, typename DistType> NameType Graph<NameType, DistType>::GetValue(int u) { //返回结点u的data值 if (u<0 || u >= this->MaxNum) { cout << "请输入正确的结点编号" << endl; return NULL; } return nodetable[u].data;
} template<typename NameType, typename DistType> DistType Graph<NameType, DistType>::GetWeight(int u, int v) { //返回u和v之间的边权 if (u >= 0 && u<this->numvertex && v >= 0 && v<this->numvertex) { if (u == v) { return 0; } Edge<DistType> *pmove = nodetable[u].adj; while (pmove) { if (pmove->dest == v) { return pmove->cost; } pmove = pmove->next; } } return Infinity; //返回无穷大表示u和v两点间不存在边 } template<typename NameType, typename DistType> int Graph<NameType, DistType>::Getvertexpos(const NameType Data) { //返回data值为Data的结点编号 for (int i = 0; i<this->numvertex; i++) { if (Data == nodetable[i].data) { return i; } } return -1; //不存在返回-1 } template<typename NameType, typename DistType> bool Graph<NameType, DistType>::InsertEdge(int u, int v, DistType weight) { //将u和v之间的边权设置为weight if (u >= 0 && u<this->numvertex && v >= 0 && v<this->numvertex) { Edge<DistType> *pmove = nodetable[u].adj; if (NULL == pmove) { //以u为起点的边不存在 nodetable[u].adj = new Edge<DistType>(v, weight); return 1; } while (pmove->next) { //逐一检查以u为起点的边,看是否存在u和v之间的边 if (pmove->dest == v) { break; } pmove = pmove->next; } if (pmove->dest == v) { //u和v之间的边已经存在,之间修改即可 pmove->cost = weight; return 1; } else { pmove->next = new Edge<DistType>(v, weight); //不存在u和v的边,直接申请一个新的边 return 1; } } return 0; } template<typename NameType, typename DistType> bool Graph<NameType, DistType>::InsertVertex(int u, const NameType Data) { //插入一个新的结点,data值为Data if (this->GetValue(u) == NULL) this->numvertex++; this->nodetable[u].data = Data; return 1; } template<typename NameType, typename DistType> bool Graph<NameType, DistType>::RemoveEdge(int u, int v) { //移除结点u和v的边 if (u >= 0 && u<this->numvertex && v >= 0 && v<this->numvertex) { Edge<DistType> *pmove = this->nodetable[u].adj, *pdel; if (NULL == pmove) { printf("结点%d和结点%d之间的边不存在\n", u, v); return 0; } if (pmove->dest == v) { //链首即是要移除的边 this->nodetable[u].adj = pmove->next; delete pmove; return 1; } while (pmove->next) { if (pmove->next->dest == v) { pdel = pmove->next; pmove->next = pdel->next; delete pdel; return 1; } pmove = pmove->next; } } printf("结点%d和结点%d之间的边不存在\n", u, v); return 0; } template<typename NameType, typename DistType> void Graph<NameType, DistType>::intputGraph(DistType maps[][100]) { //将二维数组maps[][100]当成邻接矩阵输入图中 for (int i = 0; i < this->MaxNum; i++) { this->InsertVertex(i, i); } for (int i = 0; i < MaxNum; i++) { for (int j = 0; j < MaxNum; j++) { map[i][j] = maps[i][j]; if (map[i][j] != this->Infinity) { this->InsertEdge(i, j, map[i][j]); this->InsertEdge(j, i, map[i][j]); } } } } template<typename NameType, typename DistType> void Graph<NameType, DistType>::Print() { //输出图,输出每一个结点u和它的所有连边的目标结点已以及相应的边权 Edge<DistType> *pmove; for (int i = 0; i<this->MaxNum; i++) flag[i] = 0; cout << "*******生成树的边的序偶表示*******" << endl; for (int i = 0; i<this->MaxNum; i++) { //if (nodetable[i].data == NULL) //continue; NameType u = this->nodetable[i].data; flag[i] = 1; //cout << this->nodetable[i].data << "--->"; pmove = this->nodetable[i].adj; while (pmove) { if (flag[pmove->dest] == 0) { NameType v = this->nodetable[pmove->dest].data; DistType Cost = pmove->cost; //cout << pmove->cost << "--->" << this->nodetable[pmove->dest].data << "--->"; cout << "(" << u << "," << v << ")=" << Cost << " "; } pmove = pmove->next; } //cout << "NULL" << endl; } cout << endl; } template<typename NameType, typename DistType> void Graph<NameType, DistType>::Print2() { //输出图,输出每一个结点u和它的所有连边的目标结点已以及相应的边权 Edge<DistType> *pmove; for (int i = 0; i<this->MaxNum; i++) flag[i] = 0; for (int i = 0; i<this->MaxNum; i++) { int u = i; flag[i] = 1; pmove = this->nodetable[i].adj; while (pmove) { int v = pmove->dest; if (flag[v] == 0) { DistType Cost = pmove->cost; map[u][v] = map[v][u] = Cost; } pmove = pmove->next; } } cout << "*******图的邻接矩阵表示*******" << endl; for (int i = 0; i<this->MaxNum; i++) { for (int j = 0; j<this->MaxNum; j++) { cout << map[i][j]; if (j == this->MaxNum - 1) cout << endl; else cout << " "; } }
} template<typename NameType, typename DistType> void Graph<NameType, DistType>::DFSprint(int s) { //深度优先生成一棵树(或者森林) for (int i = 0; i <= this->MaxNum; i++) flag[i] = false; cout << "*******深度优先生成一棵树(或者森林)*******" << endl; cout << "head-->" << s << "-->"; flag[s] = 1; this->DFS(s); cout << "over" << endl; for (int i = 0; i < this->MaxNum; i++) { if (flag[i] == 0) { flag[i] = 1; cout << "head-->" << i << "-->"; this->DFS(i); cout << "over" << endl; } } return; } template<typename NameType, typename DistType> void Graph<NameType, DistType>::DFS(int s) { //深度优先生成一棵树(或者森林) Edge<DistType> *pmove = nodetable[s].adj; while (pmove != NULL) { if (flag[pmove->dest] == 0) { flag[pmove->dest] = 1; cout << pmove->dest << "-->"; this->DFS(pmove->dest); } pmove = pmove->next; } return; } template<typename NameType, typename DistType> void Graph<NameType, DistType>::BFSprint(int s) { //广度优先生成一棵树(或者森林) //int *que=new int[this->MaxNum + 10]; //memset(flag, 0, sizeof(this->MaxNum + 10)); for (int i = 0; i <= this->MaxNum; i++) flag[i] = false; cout << "*******广度优先生成一棵树(或者森林)*******" << endl; flag[s] = 1; BFS(s); for (int i = 0; i<this->MaxNum; i++) { if (flag[i] == 0) { flag[i] = 1; BFS(i); } } return; } template<typename NameType, typename DistType> void Graph<NameType, DistType>::BFS(int s) { //广度优先生成一棵树(或者森林) int que[100]; int l = 0, r = 0; que[r++] = s; flag[s] = 1; while (l < r) { int u = que[l++]; Edge<DistType> *pmove = nodetable[u].adj; while (pmove != NULL) { int v = pmove->dest; if (flag[v] == 0) { que[r++] = v; flag[v] = 1; } pmove = pmove->next; } } cout << "head-->"; for (int i = 0; i < l; i++) { printf("%d%s", que[i], i == l - 1 ? "-->over\n" : "-->"); } return; } int main() { cout << "请输入图的结点数目:"; int n, maps[100][100]; cin >> n; //(1)图的点数 cout << "请输入图的邻接矩阵:" << endl for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { cin >> maps[i][j]; //(2)输入邻接矩阵 } } Graph<int, int> graph(n); //(3)建立一个具有n个顶点的图 graph.intputGraph(maps); //(4)将二位数组maps当成图的邻接矩阵进行建图 graph.Print(); //(5)按照树的序偶表示的方式输出图的连边 graph.Print2(); //(6)输出图的邻接矩阵 int pos; cout << "请输入图的遍历起始点:"; cin >> pos; //(7)输入图的遍历的起始点 graph.DFSprint(pos); //(8)输出图的深度优先生成树 graph.BFSprint(pos); //(9)输出图的广度优先生成树 graph.RemoveEdge(3, 6); //(10)将结点3和结点6之间的连边撤销,使连通图变成不连通图 graph.InsertEdge(0, 1, 2); //(11)将结点0和结点1之间的连边的边权设置为2 graph.InsertEdge(0, 2, 3); //(12)将结点0和结点2之间建立一条新的边,边权为3 graph.InsertEdge(7, 8, 4); //(13)将结点7和结点8之间的连边的边权设置为4 graph.Print(); //(14)按照树的序偶表示的方式输出图的连边 graph.Print2(); //(15)输出图的邻接矩阵 cout << "请输入图的遍历起始点:"; cin >> pos; //(16)输入图的遍历的起始点 graph.DFSprint(pos); //(17)输出图的深度优先生成树 graph.BFSprint(pos); //(18)输出图的广度优先生成树 return 0; } 实验过程原始数据记录
0 1 -1 1 -1 -1 -1 -1 -1 1 0 1 -1 1 -1 -1 -1 -1 -1 1 0 1 1 1 -1 -1 -11 -1 1 0 -1 1 1 -1 -1 -1 1 1 -1 0 -1 -1 -1 -1 -1 -1 1 1 1 0 -1 -1 -1 -1 -1 -1 1 -1 -1 0 1 1 -1 -1 -1 -1 -1 -1 1 0 1 -1 -1 -1 -1 -1 -1 1 1 0 3.建立一个具有n个顶点的图 4.将二位数组maps当成图的邻接矩阵进行建图 5.按照树的序偶表示的方式输出图的连边 *******生成树的边的序偶表示******* (0,1)=1 (0,3)=1 (1,2)=1 (1,4)=1 (2,3)=1 (2,4)=1 (2,5)=1 (3,5)=1 (3,6)=1 (4,5)=1 (6,7)=1 (6,8)=1 (7,8)=1 6.输出图的邻接矩阵 *******图的邻接矩阵表示******* 0 1 -1 1 -1 -1 -1 -1 -1 1 0 1 -1 1 -1 -1 -1 -1 -1 1 0 1 1 1 -1 -1 -1 1 -1 1 0 -1 1 1 -1 -1 -1 1 1 -1 0 -1 -1 -1 -1 -1 -1 1 1 1 0 -1 -1 -1 -1 -1 -1 1 -1 -1 0 1 1 -1 -1 -1 -1 -1 -1 1 0 1 -1 -1 -1 -1 -1 -1 1 1 0
7.输入图的遍历的起始点0 8.输出图的深度优先生成树 *******深度优先生成一棵树(或者森林)******* head-->0-->1-->2-->3-->5-->4-->6-->7-->8-->over 9.输出图的广度优先生成树 *******广度优先生成一棵树(或者森林)******* head-->0-->1-->3-->2-->4-->5-->6-->7-->8-->over
10.将结点3和结点6之间的连边撤销,使连通图变成不连通图 11.将结点0和结点1之间的连边的边权设置为2 12.将结点0和结点2之间建立一条新的边,边权为3 13.将结点7和结点8之间的连边的边权设置为4 14.按照树的序偶表示的方式输出图的连边 *******生成树的边的序偶表示******* (0,1)=2 (0,3)=1 (0,2)=3 (1,2)=1 (1,4)=1 (2,3)=1 (2,4)=1 (2,5)=1 (3,5)=1 (4,5)=1 (6,7)=1 (6,8)=1 (7,8)=4 15.输出图的邻接矩阵 *******图的邻接矩阵表示******* 0 2 3 1 -1 -1 -1 -1 -1 2 0 1 -1 1 -1 -1 -1 -1 3 1 0 1 1 1 -1 -1 -1 1 -1 1 0 -1 1 1 -1 -1 -1 1 1 -1 0 1 -1 -1 -1 -1 -1 1 1 1 0 -1 -1 -1 -1 -1 -1 1 -1 -1 0 1 1 -1 -1 -1 -1 -1 -1 1 0 4 -1 -1 -1 -1 -1 -1 1 4 0 16.输入图的遍历的起始点3 17.输出图的深度优先生成树,此时是生成的是森林 *******深度优先生成一棵树(或者森林)******* head-->3-->0-->1-->2-->4-->5-->over head-->6-->7-->8-->over 18.输出图的广度优先生成树,此时生成的是森林 *******广度优先生成一棵树(或者森林)******* head-->3-->0-->2-->5-->1-->4-->over head-->6-->7-->8-->over 五、实验结果及分析 图的顶点个数和邻接矩阵由键盘输入,在图中存储了图的邻接矩阵,另外图中的每一个结点都有相应的data值和一个链首,链表存储的是这个顶点的连边,边上有相应的边权和目标点。插入一个新的结点的data值,插入一条新的连边,修改和撤销原本存在的连边,按照树的序偶表示的方式输出图的连边和输出图的邻接矩阵,以及深度和广度优先遍历生成一棵树(或者森林)的操作基本是在点和点的边的链表之间的操作。在 按照树的序偶表示的方式输出图的连边时,由于可能一条边遍历的时候会输出两次,需要标记已经输出的边,防止重复。在输出图的邻接矩阵时,由于在上述的操作中,基本是对点和点的边链表进行操作的,需要按照目前链表的信息更新图的邻接矩阵的信息,再输出。在深度优先生成一棵树(或者森林)输出的时候,由于可能是不连通图,先把键盘输入的起始点的深度优先遍历的图输出(void DFSprint(int s)),标记输出的点,然后遍历图中所有的点,查找没有遍历过的点,再对它进行深度优先遍历(函数void DFS(int s) ),再标记输出的点,重复这个操作,直到所有的点输出。在广度优先生成一棵树(或者森林)时,由于可能是不连通图,先把键盘输入的起始点的广度优先遍历的图输出(void DFSprint(int s)),标记输出的点,然后遍历图中所有的点,查找没有遍历过的点,再对它进行广度优先遍历(函数void DFS(int s) ),再标记输出的点,重复这个操作,直到所有的点输出。在广度优先遍历生成一棵树的时候,需要用数组和双指针来模拟队列,需要注意的是,在class里面定义的int *flag,不能直接用memset(flag,0,sizeof(flag))进行初始化,会出现初始化出错,需要一个循环一个个初始化。 通过本次实验,掌握了把图转化为程序能识别的邻接矩阵理解了图的遍历方法及对应的生成树。通过深度和广度优先遍历图生成树,对图和树的数据结构有了更深的了解,将邻接矩阵转换成图中的点集和边集的关系,用链表存储关于点的边集,并通过处理点集和点的边的链表,实现图的点的添加,修改data,以及插入,修改,删除边的信息,实现对图的深度和广度遍历,对于链表的使用更加熟悉了。
|
||||||||
//源代码:
#include
using namespace std;
template class Edge {
public:
Edge(int dest, DistType cost) : dest(dest), cost(cost), next(NULL) {}
public:
int dest;
DistType cost;
Edge *next;
};
template class Vertex {
public:
Vertex() : adj(NULL) {}
NameType data;
Edge *adj;
~Vertex();
};
template Vertex::~Vertex() {
Edge *pmove = adj;
while (pmove) {
adj = pmove->next;
delete pmove;
pmove = adj;
}
}
template class Graph {
public:
Graph(int size = DefaultSize); //建立一个有size个结点的图
~Graph();
bool GraphEmpty() const { //判断图是否为空图
return 0 == numvertex;
}
bool GraphFull() const { //判断图是否已满
return MaxNum == numvertex;
}
int NumberOfVertex() const { //返回图中结点的个数
return numvertex;
}
int NumberOfEdge() const { //返回图中的边的个数
return numedges;
}
void intputGraph(DistType maps[][100]);
NameType GetValue(int u); //返回图中结点v的data
DistType GetWeight(int u, int v); //返回结点u和结点v之间的连边的边权
bool InsertVertex(int u, const NameType Data); //在结点u插入新的Data值
bool Removevertex(int u); //移除结点u
bool InsertEdge(int v1, int v2, DistType weight = Infinity); //在结点u和结点v之间插入边Cost
bool RemoveEdge(int v1, int v2); //移除u和v之间的连边
void Print(); //输出图
void Print2(); //输出图
int Getvertexpos(const NameType Data); //返回结点data==vertex的结点序号
void DFSprint(int s); //深度优先生成一棵树(或者森林)
void DFS(int s); //深度优先生成一棵树
void BFSprint(int s); //广度优先生成一棵树(或者森林)
void BFS(int s); //广度优先生成一棵树
private:
Vertex *nodetable; //图的结点,用链表的方式存储
int numvertex; //图中结点的总数
const int MaxNum; //图中最大能存储的结点总数
static const int DefaultSize = 10; //默认情况下图的最大能存储的结点总数
static const DistType Infinity = -1; //当边权==Infinity == -1时,默认为边权无穷大,对应的两点之间没有边相连
int numedges; //图中的边数
bool *flag; //标记数组
DistType map[100][100]; //图的邻接矩阵
};
template Graph::Graph(int size) //建立一个有size个结点的图
: numvertex(0), MaxNum(size), numedges(0) {
nodetable = new Vertex[size];
flag = new bool[size];
for (int i = 0; i < MaxNum; i++)
nodetable[i].data = NULL;
}
template Graph::~Graph() { //撤销图,将图中申请的结点和边的释放
Edge *pmove;
for (int i = 0; inumvertex; i++) {
pmove = this->nodetable[i].adj;
if (pmove) {
this->nodetable[i].adj = pmove->next;
delete pmove;
pmove = this->nodetable[i].adj;
}
}
delete[] nodetable;
}
template NameType Graph::GetValue(int u) { //返回结点u的data值
if (u<0 || u >= this->MaxNum) {
cout << "请输入正确的结点编号" << endl;
return NULL;
}
return nodetable[u].data;
}
template DistType Graph::GetWeight(int u, int v) { //返回u和v之间的边权
if (u >= 0 && unumvertex && v >= 0 && vnumvertex) {
if (u == v) {
return 0;
}
Edge *pmove = nodetable[u].adj;
while (pmove) {
if (pmove->dest == v) {
return pmove->cost;
}
pmove = pmove->next;
}
}
return Infinity; //返回无穷大表示u和v两点间不存在边
}
template int Graph::Getvertexpos(const NameType Data) { //返回data值为Data的结点编号
for (int i = 0; inumvertex; i++) {
if (Data == nodetable[i].data) {
return i;
}
}
return -1; //不存在返回-1
}
template bool Graph::InsertEdge(int u, int v, DistType weight) { //将u和v之间的边权设置为weight
if (u >= 0 && unumvertex && v >= 0 && vnumvertex) {
Edge *pmove = nodetable[u].adj;
if (NULL == pmove) { //以u为起点的边不存在
nodetable[u].adj = new Edge(v, weight);
return 1;
}
while (pmove->next) { //逐一检查以u为起点的边,看是否存在u和v之间的边
if (pmove->dest == v) {
break;
}
pmove = pmove->next;
}
if (pmove->dest == v) { //u和v之间的边已经存在,之间修改即可
pmove->cost = weight;
return 1;
}
else {
pmove->next = new Edge(v, weight); //不存在u和v的边,直接申请一个新的边
return 1;
}
}
return 0;
}
template bool Graph::InsertVertex(int u, const NameType Data) { //插入一个新的结点,data值为Data
if (this->GetValue(u) == NULL)
this->numvertex++;
this->nodetable[u].data = Data;
return 1;
}
template bool Graph::RemoveEdge(int u, int v) { //移除结点u和v的边
if (u >= 0 && unumvertex && v >= 0 && vnumvertex) {
Edge *pmove = this->nodetable[u].adj, *pdel;
if (NULL == pmove) {
printf("结点%d和结点%d之间的边不存在\n", u, v);
return 0;
}
if (pmove->dest == v) { //链首即是要移除的边
this->nodetable[u].adj = pmove->next;
delete pmove;
return 1;
}
while (pmove->next) {
if (pmove->next->dest == v) {
pdel = pmove->next;
pmove->next = pdel->next;
delete pdel;
return 1;
}
pmove = pmove->next;
}
}
printf("结点%d和结点%d之间的边不存在\n", u, v);
return 0;
}
template void Graph::intputGraph(DistType maps[][100]) { //将二维数组maps[][100]当成邻接矩阵输入图中
for (int i = 0; i < this->MaxNum; i++) {
this->InsertVertex(i, i);
}
for (int i = 0; i < MaxNum; i++) {
for (int j = 0; j < MaxNum; j++) {
map[i][j] = maps[i][j];
if (map[i][j] != this->Infinity) {
this->InsertEdge(i, j, map[i][j]);
this->InsertEdge(j, i, map[i][j]);
}
}
}
}
template void Graph::Print() { //输出图,输出每一个结点u和它的所有连边的目标结点已以及相应的边权
Edge *pmove;
for (int i = 0; iMaxNum; i++)
flag[i] = 0;
cout << "*******生成树的边的序偶表示*******" << endl;
for (int i = 0; iMaxNum; i++) {
//if (nodetable[i].data == NULL)
//continue;
NameType u = this->nodetable[i].data;
flag[i] = 1;
//cout << this->nodetable[i].data << "--->";
pmove = this->nodetable[i].adj;
while (pmove) {
if (flag[pmove->dest] == 0) {
NameType v = this->nodetable[pmove->dest].data;
DistType Cost = pmove->cost;
//cout << pmove->cost << "--->" << this->nodetable[pmove->dest].data << "--->";
cout << "(" << u << "," << v << ")=" << Cost << " ";
}
pmove = pmove->next;
}
//cout << "NULL" << endl;
}
cout << endl;
}
template void Graph::Print2() { //输出图,输出每一个结点u和它的所有连边的目标结点已以及相应的边权
Edge *pmove;
for (int i = 0; iMaxNum; i++)
flag[i] = 0;
for (int i = 0; iMaxNum; i++) {
int u = i;
flag[i] = 1;
pmove = this->nodetable[i].adj;
while (pmove) {
int v = pmove->dest;
if (flag[v] == 0) {
DistType Cost = pmove->cost;
map[u][v] = map[v][u] = Cost;
}
pmove = pmove->next;
}
}
cout << "*******图的邻接矩阵表示*******" << endl;
for (int i = 0; iMaxNum; i++) {
for (int j = 0; jMaxNum; j++) {
cout << map[i][j];
if (j == this->MaxNum - 1)
cout << endl;
else
cout << " ";
}
}
}
template void Graph::DFSprint(int s) { //深度优先生成一棵树(或者森林)
for (int i = 0; i <= this->MaxNum; i++)
flag[i] = false;
cout << "*******深度优先生成一棵树(或者森林)*******" << endl;
cout << "head-->" << s << "-->";
flag[s] = 1;
this->DFS(s);
cout << "over" << endl;
for (int i = 0; i < this->MaxNum; i++) {
if (flag[i] == 0) {
flag[i] = 1;
cout << "head-->" << i << "-->";
this->DFS(i);
cout << "over" << endl;
}
}
return;
}
template void Graph::DFS(int s) { //深度优先生成一棵树(或者森林)
Edge *pmove = nodetable[s].adj;
while (pmove != NULL) {
if (flag[pmove->dest] == 0) {
flag[pmove->dest] = 1;
cout << pmove->dest << "-->";
this->DFS(pmove->dest);
}
pmove = pmove->next;
}
return;
}
template void Graph::BFSprint(int s) { //广度优先生成一棵树(或者森林)
//int *que=new int[this->MaxNum + 10];
//memset(flag, 0, sizeof(this->MaxNum + 10));
for (int i = 0; i <= this->MaxNum; i++)
flag[i] = false;
cout << "*******广度优先生成一棵树(或者森林)*******" << endl;
flag[s] = 1;
BFS(s);
for (int i = 0; iMaxNum; i++) {
if (flag[i] == 0) {
flag[i] = 1;
BFS(i);
}
}
return;
}
template void Graph::BFS(int s) { //广度优先生成一棵树(或者森林)
int que[100];
int l = 0, r = 0;
que[r++] = s;
flag[s] = 1;
while (l < r) {
int u = que[l++];
Edge *pmove = nodetable[u].adj;
while (pmove != NULL) {
int v = pmove->dest;
if (flag[v] == 0) {
que[r++] = v;
flag[v] = 1;
}
pmove = pmove->next;
}
}
cout << "head-->";
for (int i = 0; i < l; i++) {
printf("%d%s", que[i], i == l - 1 ? "-->over\n" : "-->");
}
return;
}
int main() {
cout << "请输入图的结点数目:";
int n, maps[100][100];
cin >> n; //(1)图的点数
cout << "请输入图的邻接矩阵:" << endl
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> maps[i][j]; //(2)输入邻接矩阵
}
}
Graph graph(n); //(3)建立一个具有n个顶点的图
graph.intputGraph(maps); //(4)将二位数组maps当成图的邻接矩阵进行建图
graph.Print(); //(5)按照树的序偶表示的方式输出图的连边
graph.Print2(); //(6)输出图的邻接矩阵
int pos;
cout << "请输入图的遍历起始点:";
cin >> pos; //(7)输入图的遍历的起始点
graph.DFSprint(pos); //(8)输出图的深度优先生成树
graph.BFSprint(pos); //(9)输出图的广度优先生成树
graph.RemoveEdge(3, 6); //(10)将结点3和结点6之间的连边撤销,使连通图变成不连通图
graph.InsertEdge(0, 1, 2); //(11)将结点0和结点1之间的连边的边权设置为2
graph.InsertEdge(0, 2, 3); //(12)将结点0和结点2之间建立一条新的边,边权为3
graph.InsertEdge(7, 8, 4); //(13)将结点7和结点8之间的连边的边权设置为4
graph.Print(); //(14)按照树的序偶表示的方式输出图的连边
graph.Print2(); //(15)输出图的邻接矩阵
cout << "请输入图的遍历起始点:";
cin >> pos; //(16)输入图的遍历的起始点
graph.DFSprint(pos); //(17)输出图的深度优先生成树
graph.BFSprint(pos); //(18)输出图的广度优先生成树
return 0;
}