前言:在数据结构课程中,用C++封装了一些经典的算法,所以特地开一个个人分类来记录这些算法,以便将来用到的时候能够使我回忆起来,或者当做模板使用(另一方面也将书本上的代码的一些错误改正过来,方便以后的同学参考)。
首先是第三章的图的作业,图有两种存储方法,一种是用邻接矩阵来存图(主要用于稠密图),另一种是用邻接表来存图(主要用于稀疏图)。两种存图的方式不同,但是可以通过重写虚函数,使两种方式对图的操作的函数都一样,这样就便于之后在图上的各种算法的实现(比如最小生成树,最短路,拓补排序)
这次作业是封装图的类型以及用BFS,DFS 来遍历图。BFS用队列来实现,DFS则用递归来实现。
下面是我这段代码的构造的图:
下面是代码
1、邻接矩阵实现:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<stack>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int INF = 0x7fffffff;
//边类型
template <class EdgeType>
class Edge
{
public:
int start,endd;
EdgeType weight;
Edge():start(-1),endd(-1),weight(-1){}
Edge(int s,int e,int w=-1):start(s),endd(e),weight(w){}
bool operator < (const Edge<EdgeType> e) const {
return this->weight > e.weight;
}
};
//图的抽象数据类型
template <class EdgeType>
class Graph
{
public:
int numv,nume;
bool *mark;
//构造函数
Graph(int num):numv(num),nume(0) {
mark = new bool[num+1];
memset(mark,false,sizeof(mark));
}
//析构函数
~Graph() {
delete []mark;
}
virtual Edge<EdgeType> FirstEdge(int vertex)=0;
virtual Edge<EdgeType> NextEdge(Edge<EdgeType> edge)=0;
virtual void addEdge(int s,int e,EdgeType w)=0;
// virtual void deleEdge(int s,int e)=0;
//判断该边是否为该图的边
bool IsEdge(Edge<EdgeType> edge) {
if(edge.weight == -1) {
return false;
}
return true;
}
};
//邻接矩阵类型
template<class EdgeType>
class MatGraph: public Graph<EdgeType>
{
private:
int **matrix;
public:
//构造函数
MatGraph(int num):Graph<EdgeType>(num) {
matrix = (int**)new int*[num+1];
for(int i=0;i<=num;i++) {
matrix[i] = new int [num+1];
}
for(int i=0;i<=num;i++)
memset(matrix[i],0,sizeof(matrix[i]));
// memset(matrix,0,sizeof(int)*(num+1)*(num+1));
}
//析构函数
~MatGraph() {
for(int i=0;i<=this->numv;i++) {
delete [] matrix[i];
}
delete [] matrix;
}
//加入一条边
void addEdge(int s,int e,int w=1) {
if(matrix[s][e]!=0) {
cout<<"改边已经存在,不能加入该边"<<endl;
return ;
}
matrix[s][e] = w;
}
//返回以v为起点的第一条边
Edge<EdgeType> FirstEdge(int v) {
Edge<EdgeType> tempEdge(v,-1);
for(int i=1;i<=this->numv;i++) {
if(matrix[v][i]>0) {
tempEdge.endd = i;
tempEdge.weight = matrix[v][i];
return tempEdge;
}
}
return tempEdge;
}
//返回与该边有同起点的下一条边
Edge<EdgeType> NextEdge(Edge<EdgeType> edge) {
Edge<EdgeType> tempEdge(edge.start,-1);
for(int i=edge.endd+1;i<=this->numv;i++) {
if(matrix[edge.start][i]!=0) {
tempEdge.endd = i;
tempEdge.weight = matrix[edge.start][i];
return tempEdge;
}
}
return tempEdge;
}
//递归实现以v为起点的深度优先搜索
void DFS(int v) {
cout<<"DFS: ";
memset(this->mark,false,sizeof(bool)*(this->numv+1));//将每个点标记为未访问
dfs(v);
cout<<endl;
}
void dfs(int v) {
if(!this->mark[v]) {//递归出口
cout<<v<<' ';
this->mark[v] = true;//标记该边已经访问过
for(Edge<EdgeType> edge=FirstEdge(v);this->IsEdge(edge);edge=NextEdge(edge)) {
if(!this->mark[edge.endd]) {
dfs(edge.endd);
}
}
}
}
//队列实现以v为起点的宽度优先搜索
void BFS(int v) {
//基类的成员变量和成员函数要用this来调用
memset(this->mark,false,sizeof(bool)*(this->numv+1));
queue<int> que;
que.push(v);
this->mark[v]=true;
cout<<"BFS: ";
while(!que.empty()) {
int node=que.front();
que.pop();
cout<<node<<' ';
for(Edge<EdgeType> edge=FirstEdge(node);this->IsEdge(edge);edge=NextEdge(edge)) {
// cout<<node<<"->"<<edge.endd<<endl;
if(!this->mark[edge.endd]) {
que.push(edge.endd);
this->mark[edge.endd]=true;
}
}
}
cout<<endl;
}
};
//图遍历的建图
template<class T>
void init (MatGraph<T>& graph1) {
graph1.addEdge(1,2);
graph1.addEdge(2,1);
graph1.addEdge(2,4);
graph1.addEdge(4,2);
graph1.addEdge(2,5);
graph1.addEdge(5,2);
graph1.addEdge(4,8);
graph1.addEdge(8,4);
graph1.addEdge(5,8);
graph1.addEdge(8,5);
graph1.addEdge(1,3);
graph1.addEdge(3,1);
graph1.addEdge(3,6);
graph1.addEdge(6,3);
graph1.addEdge(3,7);
graph1.addEdge(7,3);
graph1.addEdge(6,7);
graph1.addEdge(7,6);
}
int main () {
// 作业一:图的遍历(DFS、BFS)
MatGraph<int> graph1(8);
init(graph1);
graph1.DFS(1);
graph1.BFS(1);
return 0;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<stack>
using namespace std;
const int INF = 0x7fffffff;
//边类型
template <class EdgeType>
class Edge
{
public:
int start,endd;
EdgeType weight;
Edge<EdgeType> *next;
Edge():start(-1),endd(-1),weight(-1),next(0){}
Edge(int s,int e,EdgeType w=1,Edge<EdgeType> *nex=0):start(s),endd(e),weight(w),next(nex){}
bool operator < (const Edge<EdgeType> e) const {
return this->weight > e.weight;
}
};
//图的抽象数据类型
template <class EdgeType>
class Graph
{
public:
int numv,nume;
bool *mark;
//构造函数
Graph(int num):numv(num),nume(0) {
mark = new bool[num+1];
memset(mark,false,sizeof(mark));
}
//析构函数
~Graph() {
delete []mark;
}
virtual Edge<EdgeType> FirstEdge(int vertex)=0;
virtual Edge<EdgeType> NextEdge(Edge<EdgeType> edge)=0;
virtual void addEdge(int s,int e,EdgeType w)=0;
// virtual void deleEdge(int s,int e)=0
//判断该边是否为该图的边
bool IsEdge(Edge<EdgeType> edge) {
if(edge.endd == -1) {
return false;
}
return true;
}
};
//由同一个起点出发的边的链表表类型
template<class EdgeType>
class EdgeList
{
public:
Edge<EdgeType> *head;
//构造函数
EdgeList():head(0){}
};
//图的邻接表示
template<class EdgeType>
class ListGraph: public Graph<EdgeType>
{
private:
EdgeList< EdgeType > *graList;
public:
//构造函数
ListGraph(int num=0):Graph<EdgeType>(num) {
graList = new EdgeList< EdgeType >[num+1];
}
//析构函数
~ListGraph() {
delete []graList;
}
//加入一条边
void addEdge(int s,int e,EdgeType w=1) {
if(graList[s].head == NULL) {
graList[s].head = new Edge<EdgeType>(s,e,w,0);
}
else {
Edge<EdgeType> *curEdge = graList[s].head;
bool flag=false;//已经存在改边flag=true
if(curEdge->endd == e)
flag=true;
while(curEdge->next && !flag) {
curEdge = curEdge->next;
if(curEdge->endd == e) {
flag=true;
}
}
if(flag) {
//如果已经存在改边,则不用加边
cout<<"该边已存在,添加失败"<<endl;
return;
}
curEdge->next = new Edge<EdgeType>(s,e,w,0);
}
}
//返回起点为v的第一条边(邻接表中该函数没用)
Edge<EdgeType> FirstEdge(int v) {
if(graList[v].head) {
return *graList[v].head;
}
Edge<EdgeType> temp(-1,-1,-1);
return temp;
}
//返回起点为v的一条边的下一条边(邻接表中该函数没用)
Edge<EdgeType> NextEdge(Edge<EdgeType> e) {
if(e.next) {
return *e.next;
}
Edge<EdgeType> temp(-1,-1,-1);
return temp;
}
//递归实现以v为起点的深度优先搜索
void DFS(int v) {
cout<<"DFS: ";
memset(this->mark,false,sizeof(bool)*(this->numv+1));//将每个点标记为未访问
dfs(v);
cout<<endl;
}
void dfs(int v) {
if(!this->mark[v]) {//递归出口
cout<<v<<' ';
this->mark[v] = true;//标记该边已经访问过
for(Edge<EdgeType> edge=FirstEdge(v);this->IsEdge(edge);edge=NextEdge(edge)) {
if(!this->mark[edge.endd]) {
dfs(edge.endd);
}
}
}
}
//队列实现以v为起点的宽度优先搜索
void BFS(int v) {
memset(this->mark,false,sizeof(bool)*(this->numv+1));
queue<int> que;
que.push(v);
this->mark[v]=true;
cout<<"BFS: ";
while(!que.empty()) {
int node=que.front();
que.pop();
cout<<node<<' ';
for(Edge<EdgeType> edge=FirstEdge(node);this->IsEdge(edge);edge=NextEdge(edge)) {
// cout<<node<<"->"<<edge.endd<<endl;
if(!this->mark[edge.endd]) {
que.push(edge.endd);
this->mark[edge.endd]=true;
}
}
}
cout<<endl;
}
};
//图遍历的建图
template<class T>
void init (ListGraph<T>& graph1) {
graph1.addEdge(1,2);
graph1.addEdge(2,1);
graph1.addEdge(2,4);
graph1.addEdge(4,2);
graph1.addEdge(2,5);
graph1.addEdge(5,2);
graph1.addEdge(4,8);
graph1.addEdge(8,4);
graph1.addEdge(5,8);
graph1.addEdge(8,5);
graph1.addEdge(1,3);
graph1.addEdge(3,1);
graph1.addEdge(3,6);
graph1.addEdge(6,3);
graph1.addEdge(3,7);
graph1.addEdge(7,3);
graph1.addEdge(6,7);
graph1.addEdge(7,6);
}
int main () {
// 作业一:图的遍历(DFS、BFS)
ListGraph<int> graph1(8);
init(graph1);
graph1.DFS(1);
graph1.BFS(1);
return 0;
}