图的邻接矩阵实现:
#ifndef GRAPH_H //定义头文件
#define GRAPH_H
#include<string> //引入标准库中的头文件
using namespace std;
const int MaxSize=12; //图中最多顶点个数
template <class T>
class MGraph
{
public:
MGraph(T a[],int n,int e); //构造函数,初始化具有n个顶点的图
void PutVex(); //取顶点
void GetVex(int i,T v[MaxSize] ); //取图中第i个顶点数据信息
void DeleteVex(int i); //删除图中第i个顶点
void InsertVex(int num,T value); //在图中插入一个顶点,其编号为i,值为value
void DeleteArc(int i, int j); //在图中删除一条边,其依附的两个顶点的编号为i和j
void InsertArc(int i, int j,int n); //在图中插入一条边,其依附的两个顶点的编号为i和j
void DFSTraverse(int v); //深度优先遍历图
void BFSTraverse(int v); //广度优先遍历图
private:
T vertex[MaxSize]; //存放图中顶点的数组
int arc[MaxSize][MaxSize]; //存放图中边的数组
int vertexNum,arcNum; //图的顶点数和边数
};
#endif
#include<iostream>
#include <string> //引入标准库中的头文件
#include "graph.h" //引入头文件
using namespace std;
/*
*前置条件:图不存在
*输 入:无
*功 能:图的初始化
*输 出:无
*后置条件:构造一个空的图
*/
template <class T>
MGraph<T>::MGraph(T a[], int n, int e)
{
vertexNum=n; //顶点数
arcNum=e; //边数
int i,j,k;
for (i=0; i<vertexNum; i++)
vertex[i]=a[i];
for (i=0; i<vertexNum; i++) //初始化邻接矩阵
for (j=0; j<vertexNum; j++)
arc[i][j]=0;
for (k=0; k<arcNum; k++) //依次输入每一条边,并修改邻接矩阵的相应元素
{
cin>>i>>j; //边依附的两个顶点的序号
arc[i][j]=1; //置有边标志
arc[j][i]=1;
}
}
/*
*前置条件:图已存在
*输 入:无
*功 能:输出图中所有顶点的数据信息
*输 出:图中所有顶点的数据信息
*后置条件:图保持不变
*/
template <class T>
void MGraph<T>::PutVex( ) //取所有顶点
{ //假设源点是第0个顶点,即顶点序号是0
int i=0;
for(i=0;i<vertexNum;i++)
{ //输出图中所有的顶点
cout<<vertex[i]<<"\n";
}
}
/*
*前置条件:图已存在
*输入:顶点i
*功能:输出图中顶点i的数据信息
*输出:图中顶点i的数据信息
*后置条件:图保持不变
*/
template <class T>
void MGraph<T>::GetVex(int i,T v[MaxSize]) //取顶点i
{ //假设源点是第0个顶点,即顶点序号是0
v[i]=vertex[i];
if (i>vertexNum) throw "位置"; //顶点i不存在则抛出异常
else
cout<<v[i]<<"\n"; //返回顶点i
}
/*
*前置条件:图已存在
*输 入:顶点name,位置num
*功 能:在图中num位置插入一个顶点name
*输 出:如果插入不成功,抛出异常
*后置条件:如果插入成功,图中增加了一个顶点
*/
template <class T>
void MGraph<T>::InsertVex(int num,T name) //在图中插入一个顶点,其编号为i,值为value
{ //假设源点是第0个顶点,即顶点序号是0
if ( num<0|| num>vertexNum) throw "位置"; //如果num输入不正确抛出异常
int row; //行
int col; //列
int numv; //最后一个顶点所在的位置
numv = vertexNum-1;
if(num>-1) //num存在
vertexNum++; //顶点数加1
for(int i=numv;i>num-1;i--) //i从最后一个顶点的下一个位置开始循环
vertex[i]=vertex[i-1]; //把从num位置的顶点到最后一个顶点均向后移一位
vertex[num]=name; //把要插入的顶点的值放在num位置上
for(row=numv;row>=0;row--) //把从num列到最后一列的元素均向下移一列
{
for(col=numv;col>=num;col--)
arc[row][col+1]=arc[row][col];
arc[row][num]=10000;
}
for(row=numv;row>=num;row--) //把从num行到最后一行的元素均向下移一行
for(col=0;col<=numv+1;col++)
arc[row+1][col]=arc[row][col];
for(col=0;col<vertexNum;col++)
arc[num][col]=10000; //把num位置所在的行、列的值均置为无穷大
}
/*
*前置条件:图已存在
*输 入:顶点pos
*功 能:在图中删除顶点pos
*输 出:如果删除不成功,抛出异常
*后置条件:如果删除成功,图中减少了一个顶点,相应顶点所建立的边也消去
*/
template <class T>
void MGraph<T>::DeleteVex(int pos) //删除第pos个顶点
{ //假设源点是第0个顶点,即顶点序号是0
if ( pos<0|| pos>MaxSize) throw "位置"; //如果pos输入不正确抛出异常
int row; //行
int col; //列
int numv=vertexNum; //numv等于顶点数
if(pos>-1){ //pos存在
for(int i=pos;i<numv-1;i++)
vertex[i]=vertex[i+1]; //把从pos到最后的每个点的位置依次向前移一位
vertexNum--; //顶点数减1
for(row=0;row<numv;row++)
{
for(col=pos;col<numv;col++)
arc[row][col]=arc[row][col+1]; //把从pos列到最后一列的元素均向前移一列
arc[row][numv-1]=10000; //把pos所在的列上的值置为无穷大
}
for(row=pos;row<numv;row++)
for(col=0;col<numv;col++)
arc[row][col]=arc[row+1][col]; //把从pos行到最后一行的元素均向上移一行
}
}
/*
*前置条件:图已存在
*输 入:顶点n、w
*功 能:在图中删除顶点n、w 依附的边
*输 出:如果删除不成功,抛出异常
*后置条件:如果删除成功,图中减少了一条边
*/
template <class T>
void MGraph<T>::DeleteArc(int n, int w) //在图中删除一条边,其依附的两个顶点的编号为i和j
{
if ( n>MaxSize|| w>MaxSize) throw "位置"; //如果输入不正确抛出异常
arc[n][w]=arc[w][n]=10000;
}
/*
*前置条件:图已存在
*输 入:顶点i、j
*功 能:在图中插入顶点i、j及其所依附的边
*输 出:如果插入不成功,抛出异常
*后置条件:如果插入成功,图中增加了一条边
*/
template <class T>
void MGraph<T>::InsertArc(int i, int j,int n) //在图中插入一条边,其依附的两个顶点的编号为i和j
{
if ( i>MaxSize|| j>MaxSize) throw "位置"; //如果输入不正确抛出异常
arc[i][j]=n;
arc[j][i]=n;
cout<<"从"<<vertex[i]<<"到"<<vertex[j]<<"的路径长度为:"<<arc[i][j]<<"\n"; //输出插入的两顶点之间的路径
}
/*
*前置条件:图已存在
*输 入:遍历的起始顶点v
*功 能:从顶点v出发深度优先遍历图
*输 出:图中顶点的一个线性排列
*后置条件:图保持不变
*/
int visited[MaxSize];
template <class T>
void MGraph<T>::DFSTraverse(int v) //深度优先遍历图
{
if ( v>vertexNum) throw "位置"; //如果输入不正确抛出异常
cout<<vertex[v]<<" ";
visited[v]=1; //已访问v顶点
for (int j=0; j<vertexNum; j++)
{
if (arc[v][j]<10000 && visited[j]==0)
DFSTraverse(j);
}
}
/*
*前置条件:图已存在
*输 入:遍历的起始顶点v
*功 能:从顶点v出发广度优先遍历图
*输 出:图中顶点的一个线性排列
*后置条件:图保持不变
*/
int visited2[MaxSize];
template <class T>
void MGraph<T>::BFSTraverse(int v) //广度优先遍历图
{
//
if ( v>vertexNum) throw "位置"; //如果输入不正确抛出异常
int front=-1;
int rear=-1; //初始化队列,假设队列采用顺序存储且不会发生溢出
cout<<vertex[v]<<" "; //被访问顶点入队
visited2[v]=1;
int Q[MaxSize];
Q[++rear]=v;
while (front!=rear)
{
v=Q[++front]; //将队头元素出队并送到v中
for (int j=0; j<vertexNum; j++)
if (arc[v][j]<10000 && visited2[j]==0 ){
cout<<vertex[j]<<" ";
visited2[j]=1;
Q[++rear]=j;
}
}
}
#include <iostream>
#include <string> //引入标准库中的头文件
#include "graph.cpp" //引用graph.cpp文件
using namespace std;
int main(int argc, char* argv[])
{
int i;
int choose=1; //控制
int which; //功能选择变量
string name; //插入顶点的值
string vname[4]={"ware","house","tera","data"}; //初始化各顶点
int pos1; //顶点
int pos2; //顶点
int m;
MGraph<string> g(vname,4,0); //调用Graph程序
while ( choose==1 ) //控制
{
cout << "需要输出顶点信息请按0" << "\n"; //输入所要进行的操作的序号
cout << "需要输出任意一个顶点信息请按1" << "\n";
cout << "需要边的信息输出请按2" << "\n";
cout << "需要删除请按3" << "\n";
cout << "需要插入请按4" << "\n";
cout << "需要删除某条边请按5" << "\n";
cout << "需要插入某条边请按6" << "\n";
cout << "需要深度优先遍历请按7" << "\n";
cout << "需要广度优先遍历请按8" << "\n";
cout << "需要退出请按10" << "\n";
cin >> which;
switch( which ) //功能选择
{
case 0: //输出图的各顶点的值
g.PutVex();
break;
case 1: //输出图的任意顶点的值
try
{
int i;
cout<<"请输入顶点:"<<"\n";
cin>>i;
g.GetVex(i,vname);
}
catch(char*)
{
cout<<"输出不正确!"<<endl;
}
break;
case 2: //输出图中的边
cout<<"所有的边的信息为:"<<"\n";
try
{
g.InsertArc(0,1,23); //插入边
g.InsertArc(1,2,34);
g.InsertArc(2,3,12);
}
catch(char*)
{
cout<<"输出不正确!"<<endl;
}
break;
case 3: //删除hh顶点
int hh ;
cout<<"请输入要删除的顶点"<<"\n";
cin>>hh;
try
{
g.DeleteVex(hh);
}
catch(char*)
{
cout<<"删除失败!"<<endl;
}
break;
case 4: //在nn位置插入值为name的顶点
int nn ;
cout<<"请输入要插入的顶点位置及名称"<<"\n";
cin>>nn>>name;
try
{
g.InsertVex(nn,name);
}
catch(char*)
{
cout<<"插入失败!"<<endl;
}
break;
case 5: //删除两顶点之间的路径
cout<<"请输入两顶点:"<<"\n";
cin>>pos1>>pos2;
try
{
g.DeleteArc(pos1,pos2);
}
catch(char*)
{
cout<<"插入失败!"<<endl;
}
break;
case 6: //插入一条边
cout<<"请输入两顶点:"<<"\n";
cin>>pos1>>pos2;
cout<<"请输入路径:"<<"\n";
cin>>m;
try
{
g.InsertArc(pos1,pos2,m);
}
catch(char*)
{
cout<<"插入失败!"<<endl;
}
break;
case 7: //深度遍历
cout<<"请输入顶点:"<<"\n";
for (i=0; i<MaxSize; i++)
visited[i] = 0;
int mm;
cin>>mm;
try
{
g.DFSTraverse(mm);
}
catch(char*)
{
cout<<"输入失败!"<<endl;
}
break;
case 8: //广度遍历
cout<<"请输入顶点:"<<"\n";
int visited2[MaxSize];
for (i=0; i<MaxSize; i++)
visited2[i]=0;
int mr;
cin>>mr;
try
{
g.BFSTraverse(mr);
cout<<"\n";
}
catch(char*)
{
cout<<"输入失败!"<<endl;
}
break;
case 10: //退出
choose=0;
break;
}
}
return 0;
}
图的邻接链表实现:
//graph.h
#ifndef GRAPH_H //定义头文件
#define GRAPH_H
using namespace std;
const int MaxSize=12;
struct ArcNode //定义边表结点
{
int adjvex; //邻接点域
ArcNode *next; //指向下一个边结点的指针
};
template <class T>
struct VertexNode //定义顶点表结点
{
T vertex; //顶点的名称
ArcNode *firstedge; //边表的头指针
};
template <class T>
class ALGraph
{
public:
ALGraph(T a[ ], int n, int e); //构造函数,初始化一个有n个顶点e条边的图
~ALGraph(); //析构函数,释放邻接表中各边表结点的存储空间
T GetVex(int i); //取图中第i个顶点数据信息
void PutVex(int i, T value); //将图中第i个顶点的数据域置为value
void InsertVex(int i, T value); //在图中插入一个顶点,其编号为i,值为value
void DeleteVex(int i); //删除图中第i个顶点
void InsertArc(int i, int j); //在图中插入一条边,其依附的两个顶点的编号为i和j
void DeleteArc(int i, int j); //在图中删除一条边,其依附的两个顶点的编号为i和j
void DFSTraverse(int v); //深度优先遍历图
void BFSTraverse(int v); //广度优先遍历图
private:
VertexNode<T> adjlist[MaxSize]; //存放顶点表的数组
int vertexNum, arcNum; //图的顶点数和边数
};
#endif
//graph.cpp
#include<iostream>
#include "graph.h"//引入头文件
/*
*前置条件:图不存在
*输 入:无
*功 能:图的初始化
*输 出:无
*后置条件:得到一个有向图
*/
template <class T>
ALGraph<T>::ALGraph(T a[ ], int n, int e)
{
arcNum = e; //边数
vertexNum=n; //顶点数
int i,j;
for (i=0; i<vertexNum; i++)
{
VertexNode<T> tempvertex;
tempvertex.vertex = a[i];
tempvertex.firstedge = NULL;
adjlist[i] = tempvertex;
}
for (int k=0; k<arcNum; k++) //依次输入每一条边,并在相应边表中插入结点
{
cout<<"请输入边所依附的两个顶点的序号";
cin>>i>>j; //输入边所依附的两个顶点的序号
ArcNode *s=new ArcNode; s->adjvex=j; //生成一个边表结点s
s->next=adjlist[i].firstedge; //将结点s插入到结点i的边表的表头
adjlist[i].firstedge=s;
}
InsertArc(0,1); //插入边
InsertArc(0,2);
InsertArc(0,3);
InsertArc(1,3);
InsertArc(1,4);
InsertArc(2,0);
InsertArc(2,4);
InsertArc(3,1);
InsertArc(3,4);
InsertArc(4,2);
InsertArc(4,3);
}
/* 前置条件:图已存在
* 输 入:无
* 功 能:销毁图
* 输 出:无
* 后置条件:释放图所占用的存储空间
*/
template <class T>
ALGraph<T>::~ALGraph( )
{
for (int i=0; i<vertexNum; i++)
{
ArcNode * p=adjlist[i].firstedge;
while (p!=NULL) //循环删除
{
adjlist[i].firstedge=p->next;
delete p; //释放结点空间
p=adjlist[i].firstedge;
}
}
}
/*
*前置条件:图已存在
*输 入:顶点i
*功 能:输出图中顶点i的数据信息
*输 出:图中顶点i的数据信息
*后置条件:图保持不变
*/
template <class T>
T ALGraph<T>::GetVex(int i)
{
if ( i>vertexNum || i<0 ) throw "输入顶点的位置不正确"; //顶点i不存在则抛出异常
return adjlist[i].vertex; //返回第i个顶点的数据域
}
/*
*前置条件:图已存在
*输 入:顶点i
*功 能:将图中顶点i的数据域置为value
*输 出:无
*后置条件:图保持不变
*/
template <class T>
void ALGraph<T>::PutVex(int i, T value)
{
if ( i>vertexNum || i<0 ) throw "输入顶点的位置不正确"; //顶点i不存在则抛出异常
adjlist[i].vertex = value; //第i个顶点的数据域置为value
}
/*
*前置条件:图已存在
*输 入:顶点value,位置i
*功 能:在图中i位置插入一个顶点name
*输 出:如果插入不成功,抛出异常
*后置条件:如果插入成功,图中增加了一个顶点
*/
template <class T>
void ALGraph<T>::InsertVex(int i, T value)
{
if ( i>vertexNum || i<0 || i>MaxSize ) throw "输入顶点的位置不正确"; //顶点i不存在则抛出异常
vertexNum++; //顶点数加1
VertexNode<T> tempvertex;
tempvertex.vertex = value;
tempvertex.firstedge = NULL;
adjlist[i] = tempvertex; //第i个顶点的数据域置为value
}
/*
*前置条件:图已存在
*输 入:顶点i
*功 能:在图中删除顶点i
*输 出:如果删除不成功,抛出异常
*后置条件:如果删除成功,图中减少了一个顶点,相应顶点所建立的边也消去
*/
template <class T>
void ALGraph<T>::DeleteVex(int i)
{
if ( i<0 || i>MaxSize) throw "位置"; //顶点输入错误则抛出异常
int k;
for ( k=0; k<vertexNum; k++) //删掉入度边
if(k!=i) DeleteArc(k, i);
ArcNode *s; //生成一个边表结点s
if( adjlist[i].firstedge != NULL)
{
ArcNode *s;
s=adjlist[i].firstedge->next;
while(s!=NULL)
{
ArcNode *p;
p = s;
adjlist[i].firstedge->next = s->next;
s=s->next;
delete p; //删除p结点
}
s=adjlist[i].firstedge;
adjlist[i].firstedge=NULL;
delete s;
}
for (k=i; k<vertexNum; k++)
{
adjlist[k]=adjlist[k+1]; //存储顶点信息
}
vertexNum--; //顶点数减1
for (k=0; k<vertexNum; k++)
if( adjlist[k].firstedge != NULL )
{
s=adjlist[k].firstedge; //将结点s插入到结点i的边表的表头
while(s!=NULL)
{
if(s->adjvex > i) //搜索i结点
s->adjvex--;
s = s->next;
}
}
}
/*
*前置条件:图已存在
*输 入:顶点i、j
*功 能:在图中插入顶点i、j及其所依附的边
*输 出:如果插入不成功,抛出异常
*后置条件:如果插入成功,图中增加了一条边
*/
template <class T>
void ALGraph<T>::InsertArc(int i, int j)
{
if ( i>MaxSize || j>MaxSize) throw "位置";//顶点输入错误则抛出异常
ArcNode *s=new ArcNode; s->adjvex=j; //生成一个边表结点s
s->next=adjlist[i].firstedge; //将结点s插入到结点i的边表的表头
adjlist[i].firstedge=s;
}
/*
*前置条件:图已存在
*输 入:顶点i、j
*功 能:在图中删除顶点i、j 依附的边
*输 出:如果删除不成功,抛出异常
*后置条件:如果删除成功,图中减少了一条边
*/
template <class T>
void ALGraph<T>::DeleteArc(int i, int j)
{
if ( i>MaxSize|| j>MaxSize) throw "位置"; //顶点输入错误则抛出异常
ArcNode *s;
ArcNode *tempnode;
s = adjlist[i].firstedge;
tempnode = adjlist[i].firstedge;
while(s!=NULL && s->adjvex!=j)
{
tempnode = s;
s = s->next;
}
if(s!=NULL)
{
tempnode->next = s->next;
delete s;
}
}
/*
*前置条件:图已存在
*输 入:遍历的起始顶点v
*功 能:从顶点v出发深度优先遍历图
*输 出:图中顶点的一个线性排列
*后置条件:图保持不变
*/
template <class T>
void ALGraph<T>::DFSTraverse(int v)
{
if ( v>vertexNum) throw "位置"; //顶点输入错误则抛出异常
ArcNode * p;
int j;
cout<<adjlist[v].vertex<<" ";
visited[v]=1;
p=adjlist[v].firstedge;
while (p) //依次搜索顶点v的邻接点j
{
j=p->adjvex;
if (visited[j]==0) DFSTraverse(j);
p=p->next;
}
}
/*
*前置条件:图已存在
*输 入:遍历的起始顶点v
*功 能:从顶点v出发广度优先遍历图
*输 出:图中顶点的一个线性排列
*后置条件:图保持不变
*/
template <class T>
void ALGraph<T>::BFSTraverse(int v)
{
if ( v>vertexNum) throw "位置"; //顶点输入错误则抛出异常
int front,rear,j;
ArcNode * p; //生成一个边表结点p
int Q[MaxSize];
front=rear=-1; //初始化队列, 假设队列采用顺序存储且不会发生溢出
cout<<adjlist[v].vertex<<" "; visited[v]=1; Q[++rear]=v; //被访问顶点入队
while (front!=rear)
{
v=Q[++front];
p=adjlist[v].firstedge; //边表中的工作指针p初始化
while (p)
{
j= p->adjvex;
if (visited[j]==0) {
cout<<adjlist[j].vertex<<" "; visited[j]=1;Q[++rear]=j;
}
p=p->next;
}
}
}
//graphmain.cpp
#include <iostream>
#include <string>
#include "graph.cpp"
using namespace std;
int visited[MaxSize];
void main( )
{
int which;
int j;
string name;
int choose=1;
string a[5] = {"北大","清华","复旦","吉林大学","长春工大"};
ALGraph<string> algraphTest( a, 5, 0); //构造图
while ( choose==1 ) //控制
{
cout << "需要输出顶点信息请按0" << endl; //输入所要进行的操作的序号
cout << "需要输出任意一个顶点信息请按1" << endl;
cout << "需要插入顶点请按2" << endl;
cout << "需要修改顶点请按3" << endl;
cout << "需要删除顶点请按4" << endl;
cout << "需要深度优先遍历请按5" << endl;
cout << "需要广度优先遍历请按6" << endl;
cout << "需要退出请按7" << endl;
cin >> which;
switch( which ) //功能选择
{
case 0:
for(j=0;j<5;j++ )
cout<<algraphTest.GetVex(j)<<" "; //输出顶点
cout<<endl;
break;
case 1:
int i;
cout<<"请输入顶点:"<<endl;
cin>>i;
try
{
cout<<algraphTest.GetVex(i)<<endl; //输出i顶点的数据域
}
catch(char* s)
{
cout<<s<<endl;
}
break;
case 2: //在图中的i位置插入一顶点值为name
cout<<"请输入顶点及名字:"<<endl;
cin>>i>>name;
try
{
algraphTest.InsertVex(i, name);
}
catch(char* s)
{
cout<<s<<endl;
}
break;
case 3: //修改图中一顶点的值
cout<<"请输入顶点及名字:"<<endl;
cin>>i>>name;
try
{
algraphTest.PutVex(i, name);
}
catch(char* s)
{
cout<<s<<endl;
}
break;
case 4: //删除图中一顶点的值
cout<<"请输入顶点:"<<endl;
cin>>i;
try
{
algraphTest.DeleteVex(i);
}
catch(char* s)
{
cout<<s<<endl;
}
break;
case 5: //图的深度优先搜索
cout<<"请输入顶点:"<<endl;
cin>>i;
cout<<endl<<"从第"<<i<<"个顶点深度优先遍历图"<<endl;
try
{
for (int ii=0; ii<MaxSize; ii++) visited[ii] = 0;
algraphTest.DFSTraverse(i);
}
catch(char* s)
{
cout<<s<<endl;
}
break;
case 6: //图的广度优先搜索
cout<<"请输入顶点:"<<endl;
cin>>i;
cout<<endl<<"从第"<<i<<"个顶点广度优先遍历图"<<endl;
try
{
for (int ii=0; ii<MaxSize; ii++) visited[ii] = 0;
algraphTest.BFSTraverse(i);
}
catch(char*s)
{
cout<<s<<endl;
}
break;
case 7: //退出
choose=0;
break;
}
}
}