实验9 图及图的操作实验
--博客后半部分有程序的所有代码--
1、图邻接矩阵存储结构表示及基本操作算法实现
(1)邻接矩阵存储结构类定义:
#include "SeqList.h" //包含动态数组结构的顺序表类
#include "SeqQueue.h" //包含静态数组结构的顺序队列类
typedef char VerT; //定义邻接矩阵图类中的VerT class AdjMWGraph
{
private:
SeqList Vertices; //顶点顺序表
int Edge[MaxVertices][MaxVertices]; //边权值数组
double numOfEdges; //边的个数
void DepthFirstSearch(const int v, int visited[]);
void BroadFirstSearch(const int v, int visited[]);
public:
AdjMWGraph(const int sz=MaxVertices); //构造函数
~AdjMWGraph(void){}; //析构函数
int NumOfVertices(void) //取顶点个数
{return Vertices.Size();}
int NumOfEdges(void) //取边的个数
{return numOfEdges;}
Void Show(); //输出邻接矩阵结果
VerT GetValue(const int v); //取顶点数值
int GetWeight(const int v1, const int v2); //取边的权值
void InsertVertex(const VerT &vertex); //插入顶点
void InsertWayEdge(const int v1, const int v2, int weight);//插入边
void InsertNoWayEdge(const int v1, const int v2, int weight);//插入边
void DeleteVertex(const int v); //删除顶点
void DeleteEdge(const int v1, const int v2); //删除边
int GetFirstNeighbor(const int v); //取第一个邻接顶点
int GetNextNeighbor(const int v1, const int v2);//取下一个邻接顶点
void DepthFirstSearch(); //深度优先遍历
void BroadFirstSearch(); //广度优先遍历
};
struct RowColWeight //网的结构体
{ int row; //行下标
int col; //列下标
int weight; //权值
};
struct RowCol //图的结构体
{
int row; //行下标
int col; //列下标
};
(2)创建邻接矩阵算法
①创建无向图邻接矩阵算法:
void CreatNoWayGraph(AdjMWGraph &G, DataType V[],int n,RowCol E[], int e)
{
//在图G中插入n个顶点
for(int i = ; i < n; i++)
G.InsertVertex(V[i]);
//在图G中插入e条边
for(int k = ; k < e; k++)
{
if(E[k].row>E[k].col)
{
cout<<"无向图参数输入错误";
exit();
}
G.InsertNoWayEdge(E[k].row, E[k].col, );
G.InsertNoWayEdge(E[k].col, E[k].row, );
}
}
②创建无向网邻接矩阵算法:
void CreatNoWayWeb(AdjMWGraph &G, DataType V[],int n,RowColWeight E[], int e)
{
//在图G中插入n个顶点
for(int i = ; i < n; i++)
G.InsertVertex(V[i]);
//在图G中插入e条边
for(int k = ; k < e; k++)
{
if(E[k].row>E[k].col)
{
cout<<"无向网参数输入错误";
exit();
}
G.InsertNoWayEdge(E[k].row, E[k].col, E[k].weight);
G.InsertNoWayEdge(E[k].col, E[k].row, E[k].weight);
}
③创建有向图邻接矩阵算法:
void CreatWayGraph(AdjMWGraph &G, DataType V[],int n,RowCol E[], int e)
//在图G中插入n个顶点V 和 e条边E
{
//在图G中插入n个顶点
for(int i = ; i < n; i++)
G.InsertVertex(V[i]);
//在图G中插入e条边
for(int k = ; k < e; k++)
G.InsertWayEdge(E[k].row, E[k].col,);
}
④创建有向网邻接矩阵算法:
void CreatWayWeb(AdjMWGraph &G, DataType V[],int n,RowColWeight E[], int e)
//在图G中插入n个顶点V 和 e条边E
{
//在图G中插入n个顶点
for(int i = ; i < n; i++)
G.InsertVertex(V[i]);
//在图G中插入e条边
for(int k = ; k < e; k++)
G.InsertWayEdge(E[k].row, E[k].col, E[k].weight);
}
(3)输出邻接矩阵结果算法
int AdjMWGraph::Show()
{
for(int i=;i<Vertices.Size();i++)
{
for(int j=;j<Vertices.Size();j++)
{
int a=GetWeight(i,j);
if(a==MaxWeight)
cout<<"∞ ";
else
cout<<a<<" ";
}
cout<<endl;
}
}
测试数据:
int main()
{
AdjMWGraph g,f;
char a[] = {'A','B','C','D','E'};
char b[] = {'A','B','C','D','E','F'}; RowColWeight r1[] ={{,,},{,,},{,,},{,,},{,,}};
RowColWeight r2[] ={{,,},{,,},{,,},{,,},{,,},{,,}};
int n1,n2,e1,e2;
n1=sizeof(a)/sizeof(a[]);
n2=sizeof(b)/sizeof(b[]);
e1=sizeof(r1)/sizeof(r1[]);
e2=sizeof(r2)/sizeof(r2[]);
CreatWayWeb(g, a, n1, r1, e1); //创建有向网
CreatNoWayWeb(f, b, n2, r2, e2); //创建无向网 cout<<"有向网:"<<endl;
g.Show(); cout<<"\n\n无向网"<<endl;
f.Show(); return ;
}
结果:
2、图的遍历递归算法
(1)(存储结构为邻接矩阵)深度优先遍历算法
void AdjMWGraph::DepthFirstSearch(const int v, int visited[])
//连通图G以v为初始顶点序号
//数组visited标记了相应顶点是否已访问过,
// 0表示未访问,1表示已访问
{
cout<<GetValue(v)<<" "; //访问该顶点
visited[v] = ; //置已访问标记
//取第一个邻接顶点
int w = GetFirstNeighbor(v);
//当邻接顶点存在时循环
while(w != -)
{
if(! visited[w])
DepthFirstSearch(w, visited); //递归
w = GetNextNeighbor(v, w); //取下一个邻接顶点
}
}
void AdjMWGraph::DepthFirstSearch()
{
int *visited = new int[NumOfVertices()];
//初始化访问标记
for(int i = ; i < NumOfVertices(); i++)
visited[i] = ;
//深度优先遍历
for(int i = ; i < NumOfVertices(); i++)
if(! visited[i])
DepthFirstSearch(i, visited);
delete []visited;
}
有向/无向网的测试结果:
(2)广度优先遍历算法
void AdjMWGraph::BroadFirstSearch(const int v, int visited[])
{
VerT u;
int w;
SeqQueue queue; //定义队列
cout<<GetValue(v)<<" "; //访问该顶点
visited[v] = ; //置已访问标记
queue.Append(v); //顶点v入队列
while(queue.NotEmpty()) //队列非空时循环
{
u = queue.Delete(); //出队列
w = GetFirstNeighbor(u); //取顶点u的第一个邻接顶点
while(w != -) //邻接顶点存在时
{
if(!visited[w]) //若该顶点没有访问过
{
cout<<GetValue(w)<<" "; //访问该顶点
visited[w] = ; //置已访问标记
queue.Append(w); //顶点w入队列
}
w = GetNextNeighbor(u, w);
}
}
} void AdjMWGraph::BroadFirstSearch()
//非连通图G访问操作为Visit()的广度优先遍历
{
int *visited = new int[NumOfVertices()];
for(int i = ; i < NumOfVertices(); i++)
visited[i] = ;
for(int i = ; i < NumOfVertices(); i++)
if(!visited[i])
BroadFirstSearch(i, visited);
delete []visited;
}
有向网/无向网的测试结果:
最后附上整体代码结构与结果
AdjMWGraph.h
#include "SeqList.h" //包含动态数组结构的顺序表类
#include "SeqQueue.h" //包含静态数组结构的顺序队列类
typedef char VerT; //定义邻接矩阵图类中的VerT class AdjMWGraph
{
private:
SeqList Vertices; //顶点顺序表
int Edge[MaxVertices][MaxVertices]; //边权值数组
double numOfEdges; //边的个数
void DepthFirstSearch(const int v, int visited[]);
void BroadFirstSearch(const int v, int visited[]);
public:
AdjMWGraph(const int sz=MaxVertices); //构造函数
~AdjMWGraph(void){}; //析构函数
void Show(); //输出邻接矩阵结果
int NumOfVertices(void) //取顶点个数
{return Vertices.Size();}
int NumOfEdges(void) //取边的个数
{return numOfEdges;}
VerT GetValue(const int v); //取顶点数值
int GetWeight(const int v1, const int v2); //取边的权值
void InsertVertex(const VerT &vertex); //插入顶点
void InsertWayEdge(const int v1, const int v2, int weight);//插入边
void InsertNoWayEdge(const int v1, const int v2, int weight);//插入边
void DeleteVertex(const int v); //删除顶点
void DeleteEdge(const int v1, const int v2); //删除边
int GetFirstNeighbor(const int v); //取第一个邻接顶点
int GetNextNeighbor(const int v1, const int v2);//取下一个邻接顶点
void DepthFirstSearch(); //深度优先遍历
void BroadFirstSearch(); //广度优先遍历
};
AdjMWGraph::AdjMWGraph(const int sz): Vertices(sz)
//构造函数 ,构造顶点个数为sz个,没有边的图
{
for(int i = ; i < sz; i++)
for(int j = ; j < sz; j++)
{
if(i == j)
Edge[i][j] = ;
else
Edge[i][j] = MaxWeight;
} // MaxWeight权值的无穷大
numOfEdges = ;
}
VerT AdjMWGraph::GetValue(const int v)
//取顶点v的数值
{
if(v < || v >= Vertices.Size())
{
cout << "参数v越界出错!" << endl;
exit();
}
return Vertices.GetData(v);
}
int AdjMWGraph::GetWeight(const int v1, const int v2)
//取起始顶点为v1、终止顶点为 v2的边的权值
{
if(v1 < || v1 >= Vertices.Size() || v2 < || v2 >= Vertices.Size())
{
cout << "参数v1或v2越界出错!" << endl;
exit();
}
return Edge[v1][v2];
} void AdjMWGraph::InsertVertex(const VerT &vertex)
//插入顶点vertex //把顶点vertex插入到顺序表的当前表尾位置
{ Vertices.Insert(vertex, Vertices.Size());
}
void AdjMWGraph::InsertWayEdge(const int v1, const int v2, int weight)
//插入一条起始顶点为v1、终止顶点为 v2、权值为weight的边
{
if(v1 < ||v1>=Vertices.Size()||v2 < ||v2 >=Vertices.Size())
{
cout << "参数v1或v2越界出错!" << endl;
exit();
}
Edge[v1][v2] = weight; //插入边
numOfEdges++; //边的个数加1
}void AdjMWGraph::InsertNoWayEdge(const int v1, const int v2, int weight)
//插入一条起始顶点为v1、终止顶点为 v2、权值为weight的边
{
if(v1 < ||v1>=Vertices.Size()||v2 < ||v2 >=Vertices.Size())
{
cout << "参数v1或v2越界出错!" << endl;
exit();
}
Edge[v1][v2] = weight; //插入边
numOfEdges+=0.5; //边的个数加0.5
}
void AdjMWGraph::DeleteVertex(const int v)
//删除顶点v
{
//删除所有包含顶点v的边
for(int i = ; i < Vertices.Size(); i++)
for(int j = ; j < Vertices.Size(); j++)
if((i == v || j == v) && i != j && Edge[i][j] > && Edge[i][j] < MaxWeight)
{
Edge[i][j] = MaxWeight; //把该边的权值置为无穷大
numOfEdges--; //边的个数减1
}
Vertices.Delete(v); //删除顶点v
}
void AdjMWGraph::DeleteEdge(const int v1, const int v2)
//删除一条起始顶点为v1、终止顶点为 v2的边
{
if(v1 < || v1 >Vertices.Size()||v2<||v2>Vertices.Size())
{
cout<<Vertices.Size();
cout << "参数v1或v2出错!" << endl;
exit();
}
if(Edge[v1][v2] == MaxWeight )
{
cout << "该边不存在!" << endl;
exit();
}
Edge[v1][v2] = MaxWeight; //把该边的权值置为无穷大
numOfEdges--; //边的个数减1
}
int AdjMWGraph::GetFirstNeighbor(const int v)
//取顶点v的第一个邻接顶点。若存在返回该顶点的下标序号,否则返回-1
{
if(v< || v> Vertices.Size())
{
cout << "参数v1越界出错!" << endl;
exit();
}
for(int col = ; col <=Vertices.Size(); col++)
if(Edge[v][col] > && Edge[v][col] < MaxWeight)
return col;
return -;
} int AdjMWGraph::GetNextNeighbor(const int v1, const int v2)
//取顶点v1的邻接顶点v2后的邻接顶点
//若存在返回该顶点的下标序号,否则返回-1
{
if(v1 < || v1 > Vertices.Size() || v2 < || v2 >Vertices.Size())
{
cout << "参数v1或v2越界出错!" << endl;
exit();
}
for(int col = v2+; col < Vertices.Size(); col++)
if(Edge[v1][col] > && Edge[v1][col] < MaxWeight)
return col;
return -;
}
void AdjMWGraph::DepthFirstSearch(const int v, int visited[])
//连通图G以v为初始顶点序号
//数组visited标记了相应顶点是否已访问过,
// 0表示未访问,1表示已访问
{
cout<<GetValue(v)<<" "; //访问该顶点
visited[v] = ; //置已访问标记
//取第一个邻接顶点
int w = GetFirstNeighbor(v);
//当邻接顶点存在时循环
while(w != -)
{
if(! visited[w])
DepthFirstSearch(w, visited); //递归
w = GetNextNeighbor(v, w); //取下一个邻接顶点
}
}
void AdjMWGraph::DepthFirstSearch()
{
int *visited = new int[NumOfVertices()];
//初始化访问标记
for(int i = ; i < NumOfVertices(); i++)
visited[i] = ;
//深度优先遍历
for(int i = ; i < NumOfVertices(); i++)
if(! visited[i])
DepthFirstSearch(i, visited);
delete []visited;
} void AdjMWGraph::BroadFirstSearch(const int v, int visited[])
{
VerT u;
int w;
SeqQueue queue; //定义队列
cout<<GetValue(v)<<" "; //访问该顶点
visited[v] = ; //置已访问标记
queue.Append(v); //顶点v入队列
while(queue.NotEmpty()) //队列非空时循环
{
u = queue.Delete(); //出队列
w = GetFirstNeighbor(u); //取顶点u的第一个邻接顶点
while(w != -) //邻接顶点存在时
{
if(!visited[w]) //若该顶点没有访问过
{
cout<<GetValue(w)<<" "; //访问该顶点
visited[w] = ; //置已访问标记
queue.Append(w); //顶点w入队列
}
w = GetNextNeighbor(u, w);
}
}
} void AdjMWGraph::BroadFirstSearch()
//非连通图G访问操作为Visit()的广度优先遍历
{
int *visited = new int[NumOfVertices()];
for(int i = ; i < NumOfVertices(); i++)
visited[i] = ;
for(int i = ; i < NumOfVertices(); i++)
if(!visited[i])
BroadFirstSearch(i, visited);
delete []visited;
}
void AdjMWGraph::Show()
{
for(int i=;i<Vertices.Size();i++)
{
for(int j=;j<Vertices.Size();j++)
{
int a=GetWeight(i,j);
if(a==MaxWeight)
cout<<"∞ ";
else
cout<<a<<" ";
}
cout<<endl;
}
}
CreatAdjMWGraph.h
struct RowColWeight //网的结构体
{ int row; //行下标
int col; //列下标
int weight; //权值
};
struct RowCol //图的结构体
{
int row; //行下标
int col; //列下标
}; void CreatWayWeb(AdjMWGraph &G, DataType V[],int n,RowColWeight E[], int e)
//在图G中插入n个顶点V 和 e条边E
{
//在图G中插入n个顶点
for(int i = ; i < n; i++)
G.InsertVertex(V[i]);
//在图G中插入e条边
for(int k = ; k < e; k++)
G.InsertWayEdge(E[k].row, E[k].col, E[k].weight);
}
void CreatNoWayWeb(AdjMWGraph &G, DataType V[],int n,RowColWeight E[], int e)
{
//在图G中插入n个顶点
for(int i = ; i < n; i++)
G.InsertVertex(V[i]);
//在图G中插入e条边
for(int k = ; k < e; k++)
{
if(E[k].row>E[k].col)
{
cout<<"无向网参数输入错误";
exit();
}
G.InsertNoWayEdge(E[k].row, E[k].col, E[k].weight);
G.InsertNoWayEdge(E[k].col, E[k].row, E[k].weight);
}
}
void CreatWayGraph(AdjMWGraph &G, DataType V[],int n,RowCol E[], int e)
//在图G中插入n个顶点V 和 e条边E
{
//在图G中插入n个顶点
for(int i = ; i < n; i++)
G.InsertVertex(V[i]);
//在图G中插入e条边
for(int k = ; k < e; k++)
G.InsertWayEdge(E[k].row, E[k].col,);
}
void CreatNoWayGraph(AdjMWGraph &G, DataType V[],int n,RowCol E[], int e)
{
//在图G中插入n个顶点
for(int i = ; i < n; i++)
G.InsertVertex(V[i]);
//在图G中插入e条边
for(int k = ; k < e; k++)
{
if(E[k].row>E[k].col)
{
cout<<"无向图参数输入错误";
exit();
}
G.InsertNoWayEdge(E[k].row, E[k].col, );
G.InsertNoWayEdge(E[k].col, E[k].row, );
}
}
SeqList.h
class SeqList
{
protected:
DataType *list; //数组
int maxSize; //最大元素个数
int size; //当前元素个数
public:
SeqList(int max=); //构造函数
~SeqList(void); //析构函数 int Size(void) const; //取当前数据元素个数
void Insert(const DataType& item, int i);//插入
DataType Delete(const int i); //删除
DataType GetData(int i) const; //取数据元素
}; SeqList::SeqList(int max) //构造函数
{
maxSize = max;
size = ;
list = new DataType[maxSize];
} SeqList::~SeqList(void) //析构函数
{
delete []list;
} int SeqList::Size(void) const //取当前数据元素个数
{
return size;
} void SeqList::Insert(const DataType& item, int i) //插入
//在指定位置i前插入一个数据元素item
{
if (size == maxSize)
{
cout << "顺序表已满无法插入!" << endl;
exit();
}
if(i < || i > size) //参数正确与否判断
{
cout << "参数i越界出错!" << endl;
exit();
} //从size-1至i逐个元素后移
for(int j = size; j > i; j--) list[j] = list[j-]; list[i] = item; //在i位置插入item
size++; //当前元素个数加1
} DataType SeqList::Delete(const int i) //删除
//删除指定位置i的数据元素,删除的元素由函数返回
{
if (size == )
{
cout << "顺序表已空无元素可删!" << endl;
exit();
}
if(i < || i > size - ) //参数正确与否判断
{
cout<<"参数i越界出错!"<<endl;
exit();
} DataType x = list[i]; //取到要删除的元素 //从i+1至size-1逐个元素前移
for(int j = i;j < size-; j++) list[j] = list[j+]; size--; //当前元素个数减1
return x; //返回删除的元素
} DataType SeqList::GetData(int i) const //取数据元素
//取位置i的数据元素,取到的数据元素由函数返回
{
if(i < || i > size - ) //参数正确与否判断
{
cout << "参数i越界出错!" << endl;
exit();
} return list[i]; //返回取到的元素
}
SeqQueue.h
class SeqQueue{
private:
DataType data[]; //顺序队列数组
int front; //队头指示器
int rear; //队尾指示器
int count; //元素个数计数器
int maxsize;
public:
SeqQueue(); //构造函数
~SeqQueue(void){}; //析构函数
void Append(const DataType& item); //入队列
int NotEmpty(void)const //非空否
{return count!=;}
DataType Delete(void); //出队列
};
SeqQueue::SeqQueue()
{
front=rear=;
count=;
};
void SeqQueue::Append(const DataType& item) //入队列
//把数据元素item插入队列作为当前的新队尾
{
if(count>&&front==rear)
{
cout<<"队列已满!"<<endl;
exit();
}
data[rear]=item; //把元素item加在队尾
rear=(rear+) % maxsize; //队尾指示器加1
count++; //计数器加1
}
DataType SeqQueue::Delete(void) //出队列
//把队头元素出队列,出队列元素由函数返回
{
if(count==)
{
cout<<"队列已空!"<<endl;
exit();
}
DataType temp=data[front]; //保存原队头元素
front=(front+) % maxsize; //队头指示器加1
count--; //计数器减1
return temp; //返回原队头元素
}
main.cpp
#include <iostream>
#include <stdlib.h>
using namespace std;
typedef char VerT; //定义邻接矩阵图类中的VerT
typedef char DataType; //定义顺序表类中的DataType
const int MaxVertices = ; //定义最大顶点个数
const int MaxWeight = ; //定义权值的无穷大
#include "AdjMWGraph.h"//包含邻接矩阵的图类
#include "CreatAdjMWGraph.h"//包含邻接矩阵图的创建函数 int main()
{
AdjMWGraph g,f;
char a[] = {'A','B','C','D','E'};
char b[] = {'A','B','C','D','E','F'}; RowColWeight r1[] ={{,,},{,,},{,,},{,,},{,,}};
RowColWeight r2[] ={{,,},{,,},{,,},{,,},{,,},{,,}};
int n1,n2,e1,e2;
n1=sizeof(a)/sizeof(a[]);
n2=sizeof(b)/sizeof(b[]);
e1=sizeof(r1)/sizeof(r1[]);
e2=sizeof(r2)/sizeof(r2[]);
CreatWayWeb(g, a, n1, r1, e1); //创建有向网
CreatNoWayWeb(f, b, n2, r2, e2); //创建无向网 cout<<"有向网:"<<endl;
g.Show();
cout << "\n顶点个数为:" << g.NumOfVertices();
cout << "\n边的条数为:" << g.NumOfEdges();
cout << "\n深度优先搜索序列为:";
g.DepthFirstSearch();
cout << "\n广度优先搜索序列为:";
g.BroadFirstSearch(); cout<<"\n\n无向网"<<endl;
f.Show();
cout << "\n顶点个数为:" << f.NumOfVertices();
cout << "\n边的条数为:" << f.NumOfEdges();
cout << "\n深度优先搜索序列为:";
f.DepthFirstSearch();
cout << "\n广度优先搜索序列为:";
f.BroadFirstSearch();
return ;
}
最终结果