无向无权图 之 一笔画问题
我大二上学期学校专业课数据结构与算法课中的三级项目是完成一个无向无权图,思考了挺长时间,觉得一笔画这个题目很适合这个无向无权图。于是很开心的开始了三级项目的完成。算法嘛,对编程思想毕竟没有那么严格的要求,我们也想尽自己的能力完善一下,给它面向对象一下,也就能这样了,能力有限,哈哈。
第一步:类的设计,我想的是构建三个类:定点类,边类,和图类。
①顶点类:有顶点的值(也就是顶点的名字),顶点的两个构造方法,顶点是否被访问,还有每个顶点与其相邻的顶点,放置在了vector数组中。话说这vector数组真是个好东西,不用自己来定义集合了,对于我这种小菜鸟来说省了好多麻烦。
#pragma once
#include<vector>
using namespace std;
class Vertex {
public :
Vertex(int value);
Vertex();
int getValue();
void setValue(int value);
vector<Vertex> & getNearVertexs();
bool isVisted;
private:
vector<Vertex> nearVertexs;
int value;
};
vector<Vertex> & Vertex::getNearVertexs() {
return nearVertexs;
}
int Vertex::getValue() {
return value;
}
void Vertex::setValue(int value) {
this->value = value;
}
Vertex::Vertex(int value) {
isVisted = false;
this->value = value;
}
Vertex::Vertex() {
isVisted = false;
}
②边类:两个构造方法,边是否被访问(因为一笔画问题是相对边来说的,要求每一条边都要被访问一次,点的访问次数不限),返回这个边的两个顶点。
#pragma once
#include"Vertex.h"
class Edge {
public:
Edge();
Edge(Vertex v1, Vertex v2);
bool isVisited;
Vertex& getVertex1();
Vertex& getVertex2();
private:
Vertex v1, v2;
};
Edge::Edge(Vertex v1, Vertex v2){
this->v1 = v1;
this->v2 = v2;
isVisited = false;
}
Vertex& Edge::getVertex1() {
return v1;
}
Vertex& Edge::getVertex2() {
return v2;
}
Edge::Edge() {
isVisited = false;
}
③图类:这里面东西有点多,具体还是看代码吧,对应函数的功能大家也能按着英语的意思大概弄个明白,也写了部分注释。
#pragma once
#include<iostream>
#include"Vertex.h"
#include"Edge.h"
using namespace std;
class arrayGraph
{
public:
arrayGraph(int e, int v);
int numberOfVertices();//点的数量
int numberOfEdges();//边的数量
vector<Edge> getEdges();//获得图中边的集合
vector<Vertex> getVertexs();//获得图中点的集合
bool existsEdge(Edge edge);//图中是否存在这条边,判断依据是边中顶点的值
void insertEdge(Edge edge);//插入一条边
void initialize();//在判断一笔画回路的时候做的一些初始化操作,把每个顶点相邻的顶点的集合存到vector数组中
void DFS(Vertex & v);//从某一顶点开始dfs
void dfs(Vertex & v);
void override_dfs(Vertex & v);//核心算法:判断一笔画路径的dfs,判断回路的过程和dfs类似
void override_DFS(Vertex& v);
Vertex& findVertexByValue(int value);//图中通过顶点值来返回相应顶点的引用
Edge& findEdgeByVertexValues(int value1, int value2);//图中通过边的两个顶点值来返回相应边的引用
bool isOk();//判断是否有一笔画路径
bool isCircled();判断是否构成环路
private:
int edge_count;
int vertex_count;
int insert_index = 0;
vector<Edge> edges;
vector<Vertex> reach;
vector<Vertex> vertexs;
vector<Vertex> temp;
bool existVertex(int value);
};
arrayGraph::arrayGraph(int e, int v) {
this->edge_count = e;
this->vertex_count = v;
for (int i = 0; i < e; i++)
{
cout << "请输入第" << i + 1 << "条边的两个顶点名" << endl;
Vertex v1, v2;
int a,b;
cin >> a >> b;
v1.setValue(a);
v2.setValue(b);
insertEdge(Edge(v1, v2));
if (!existVertex(v1.getValue())) {
vertexs.push_back(v1);
}
if (!existVertex(v2.getValue())) {
vertexs.push_back(v2);
}
}
initialize();
}
int arrayGraph::numberOfVertices() {
return vertex_count;
}
int arrayGraph::numberOfEdges() {
return edge_count;
}
vector<Edge> arrayGraph::getEdges() {
return edges;
}
bool arrayGraph::existsEdge(Edge edge) {
for each (Edge t_edge in edges)
{
if ((t_edge.getVertex1().getValue() == edge.getVertex1().getValue() && t_edge.getVertex2().getValue() == edge.getVertex2().getValue())
|| (t_edge.getVertex1().getValue() == edge.getVertex2().getValue() && t_edge.getVertex2().getValue() == edge.getVertex1().getValue())
) {
return true;
}
}
return false;
}
void arrayGraph::insertEdge(Edge edge) {
this->edges.push_back(edge);
insert_index++;
}
void arrayGraph::DFS(Vertex & v) {
reach.push_back(findVertexByValue(v.getValue()));
findVertexByValue(v.getValue()).isVisted = true;
dfs(findVertexByValue(v.getValue()));
for (vector<Vertex>::iterator i = reach.end();
i != reach.begin(); cout << (*(--i)).getValue() << " ");
cout << endl;
}
void arrayGraph::dfs(Vertex & v) {
for (vector<Vertex> ::iterator it = findVertexByValue(v.getValue()).getNearVertexs().begin();
it != findVertexByValue(v.getValue()).getNearVertexs().end(); ++it) {
if (!(*it).isVisted && !findVertexByValue((*it).getValue()).isVisted) {
(*it).isVisted = true;
findVertexByValue((*it).getValue()).isVisted = true;
reach.push_back((*it));
dfs((*it));
}
}
}
void arrayGraph::initialize() {
//把每个边中的两个顶点都放在对方的vector集合里
for each (Edge t_edge in edges)
{
Vertex v1 = t_edge.getVertex1();
Vertex v2 = t_edge.getVertex2();
cout << t_edge.getVertex1().getValue() << " " << t_edge.getVertex2().getValue() << endl;
for (vector<Vertex> ::iterator it = vertexs.begin(); it != vertexs.end(); ++it) {
if ((*it).getValue() == v1.getValue()) {
(*it).getNearVertexs().push_back(v2);
}
if ((*it).getValue() == v2.getValue()) {
(*it).getNearVertexs().push_back(v1);
}
}
}
system("cls");
cout << "=======================================================" << endl;
cout << "=======================================================" << endl;
cout << "=======================一笔画问题=======================" << endl;
cout << endl;
//迭代器的使用
for (vector<Vertex> ::iterator it = vertexs.begin(); it != vertexs.end(); ++it) {
cout << "元素" << (*it).getValue() << "的临界数组为: ";
for (vector<Vertex> ::iterator ix = (*it).getNearVertexs().begin(); ix != (*it).getNearVertexs().end(); ++ix) {
cout << "元素:" << (*ix).getValue() << " ";
}
cout << endl;
cout << endl;
}
}
vector<Vertex> arrayGraph::getVertexs() {
return vertexs;
}
bool arrayGraph::existVertex(int value) {
for each (Vertex t_v in vertexs)
{
if (t_v.getValue() == value) {
return true;
}
}
return false;
}
Vertex& arrayGraph::findVertexByValue(int value) {
for (vector<Vertex> ::iterator it = vertexs.begin(); it != vertexs.end(); ++it) {
if ((*it).getValue() == value) {
return (*it);
}
}
return Vertex();
}
void arrayGraph::override_dfs(Vertex& v) {
for (vector<Vertex> ::iterator it = vertexs.begin(); it != vertexs.end(); ++it) {
if (existsEdge(Edge(findVertexByValue(v.getValue()), (*it))) && !findEdgeByVertexValues(findVertexByValue(v.getValue()).getValue(),(*it).getValue()).isVisited) {
findEdgeByVertexValues(v.getValue(), (*it).getValue()).isVisited = true;
override_dfs((*it));
}
}
reach.push_back(findVertexByValue(v.getValue()));
}
void arrayGraph::override_DFS(Vertex& v) {
override_dfs(findVertexByValue(v.getValue()));
if (isCircled()) {
cout << "这是一个有环图,一笔画结果为:" << endl;
}
else
cout << "这是一个无环图,一笔画结果为:" << endl;
for (vector<Vertex>::iterator i = reach.end();
i != reach.begin(); cout << (*(--i)).getValue() << " ");
cout << endl;
}
Edge& arrayGraph::findEdgeByVertexValues(int value1, int value2) {
for (vector<Edge> ::iterator it = edges.begin(); it != edges.end(); ++it) {
if (((*it).getVertex1().getValue() == value1 && (*it).getVertex2().getValue() == value2) ||
((*it).getVertex1().getValue() == value2 && (*it).getVertex2().getValue() == value1)) {
return (*it);
}
}
return Edge();
}
bool arrayGraph::isOk() {
int key = 0;
for (vector<Vertex>::iterator it = vertexs.begin();it != vertexs.end();++it) {
if ((*it).getNearVertexs().size() % 2 != 0) {
temp.push_back((*it));
key++;
}
}
if (key != 0 && key != 2) {
return false;
}
else {
cout << "必须要从度为奇数的点开始遍历,否则无法完成一笔画路径!请输入以下点中之一作为七点" << endl;
for (vector<Vertex>::iterator it = temp.begin();it != temp.end();++it) {
cout << (*it).getValue() << " ";
}
cout << endl;
return true;
}
}
bool arrayGraph::isCircled() {
return reach.size()>=vertexs.size();
}
最后就是测试的main函数了
#include<iostream>
#include<conio.h>
#include"Graph.h"
using namespace std;
int main() {
while (1) {
system("cls");
cout << "=======================================================" << endl;
cout << "=======================================================" << endl;
cout << "=======================一笔画问题=======================" << endl;
cout << endl;
int edge_count, vertex_count;
cout << "输入边数和顶点数" << endl;
cin >> edge_count >> vertex_count;
arrayGraph a(edge_count, vertex_count);
cout << "图已建立!按任意键寻找一笔画结果!" << endl;
getch();
if (!a.isOk()) {
cout << "该图没有一笔画路径!" << endl;
}
else {
cout << "请输入要开始遍历的点" << endl;
int value;cin >> value;
a.override_DFS(a.findVertexByValue(value));
}
getch();
getch();
}
system("pause");
return 0;
}
希望能帮到大家!!