图的存储结构:
比较常见的两种图的存储结构:
- 邻接矩阵表示法(数组表示法)
若图G是一个具有n个顶点的无权图,G的邻接矩阵是具有以下性质的n×n矩阵A:
A [ i , j ] = { 1 i f ( v i , v j ) o r < v i , v j > ∈ V 0 o t h e r s A[i,j]=\left\{\begin{matrix} 1 &if (v_{i},v_{j})or<v_{i},v_{j}>\in V \\ 0 & others \end{matrix}\right. A[i,j]={10if(vi,vj)or<vi,vj>∈Vothers
若图G是一个具有n个顶点的网,则它的邻接矩阵是具有以下性质的n×n矩阵A:
A [ i , j ] = { w i j i f ( v i , v j ) o r < v i , v j > ∈ V ∞ o t h e r s A[i,j]=\left\{\begin{matrix} w_{ij} &if (v_{i},v_{j})or<v_{i},v_{j}>\in V \\ \infty & others \end{matrix}\right. A[i,j]={wij∞if(vi,vj)or<vi,vj>∈Vothers - 邻接表
邻接表存储方法时一种顺序分配与链式分配相结合的存储方法。邻接表中,对图中每个顶点建立一个单链表,第i个单链表中的结点表示依附于顶点 v i v_{i} vi的边。每个单链表上附设一个表头结点。表结点和表头结点的结构如下:
表头结点:
data | firstarc |
---|---|
存储顶点的名称或其他信息 | 指向链表中第一个结点 |
表结点:
adjvex | nextarc | info |
---|---|---|
指示与顶点邻接的点在图中的位置 | 指示下一条边或弧的结点 | 存储与边或弧相关的信息,如权值等 |
邻接矩阵
下面是邻接矩阵的结构定义
//邻接矩阵
typedef enum{DG, DN, UDG, UDN} GraphKind; //有向图、有向网、无向图、无向网
typedef struct ArcCell{
VRType adj; //弧的类型,图为0,1
InfoType *info; //与弧相关的信息的指针
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct
{
VertexType vexs[MAX_VERTEX_NUM]; //顶点向量
AdjMatrix arcs; //邻接矩阵
int vexnum, arcnum; //顶点数和边数
GraphKind kind; //图类型
}MGraph;
下面是利用邻接矩阵实现的基本功能:
创建图:
两种方法,第一种是文本读入,第二种是键盘输入。
文本里,第一行是结点个数,第二行是结点名称,第三行及其往下是结点与结点之间的信息(权值),如果两个结点之前没有联系就是0
void createGraph_txt(MGraph &G)
{
ifstream fin("city.txt"); //文本名称
fin>>G.vexnum;
for(int i=0;i<G.vexnum;i++){
fin>>G.vexs[i];
}
int edge = 0;
for(int i =0;i<G.vexnum;i++){
for(int j=0;j<G.vexnum;j++){
double info;
fin>>info;
if(info>0){
G.arcs[i][j].adj = info;
edge++;
}
else{
G.arcs[i][j].adj = 0;
}
}
}
G.arcnum = edge;
}
void createGraph_cin(MGraph &G)
{
cout<<"请输入结点数量:";
int city_num;
cin>>city_num;
G.vexnum = city_num;
cout<<"请输入结点名称:";
for(int i=0;i<G.vexnum;i++) cin>>G.vexs[i];
int edge = 0;
cout<<"请依次输入结点之间的权值,如果结点之间无联系,请输入0"<<endl;
for(int i=0;i<G.vexnum;i++){
for(int j=0;j<G.vexnum;j++){
double info;
cin>>info;
if(info>0){
G.arcs[i][j].adj = info;
edge ++;
}
else{
G.arcs[i][j].adj = 0;
}
}
}
G.arcnum = edge;
}
获取当前图的结点个数、有向边个数
int getNumVertices(MGraph &G)
{
return G.vexnum;
}
int getNumEdges(MGraph &G)
{
return G.arcnum;
}
判断某个顶点是否存在
bool validVertex(MGraph &G, string v)
{
int has = 0;
for(int i=0;i<G.vexnum;i++){
if(!v.compare(G.vexs[i])){
has = 1;
cout<<v<<"顶点存在"<<endl;
break;
}
}
if(has==1) return true;
else {
cout<<v<<"顶点不存在"<<endl;
return false;
}
}
判断两个顶点之间是否有边
分别获取两个顶点在图里的位置,再看对应的
<
v
i
,
v
j
>
<v_{i},v_{j}>
<vi,vj>的信息,如果是0,那就不存在有向边。
这里uv用于判断输入的两个顶点是否都存在,当有一个存在的时候就+1,这样两个都存在就加了2.
bool hasEdge(MGraph &G, string u, string v)
{
int u_index = -1, v_index = -1;
int uv = 0;
for(int i=0;i<G.vexnum;i++){
if(!u.compare(G.vexs[i])){
u_index = i;
uv ++;
if(uv==2) break;
}
else if(!v.compare(G.vexs[i])){
v_index = i;
uv ++;
if(uv==2) break;
}
}
if(G.arcs[u_index][v_index].adj==0||uv!=2){
cout<<"不存在"<<u<<"到"<<v<<"的有向边"<<endl;
return false;
}
else{
cout<<"存在"<<u<<"到"<<v<<"的有向边"<<endl;
cout<<"权值为:"<<G.arcs[u_index][v_index].adj<<endl;
return true;
}
}
添加顶点
还是先判断是否存在该顶点,如果存在就退出,如果不存在的话就加进去,加完后其余顶点和它之间的联系默认为0
void addVertex(MGraph &G, string u)
{
if(validVertex(G, u)){
cout<<"该顶点已存在,无需添加"<<endl;
return ;
}
else{
G.vexnum++;
G.vexs[G.vexnum-1] = u;
for(int i=0;i<G.vexnum-1;i++) G.arcs[i][G.vexnum].adj = 0;
for(int i=0;i<G.vexnum;i++) G.arcs[G.vexnum-1][i].adj = 0;
}
}
添加有向边
void addEdge(MGraph &G, string u, string v, int w)
{
if(hasEdge(G, u, v)){
cout<<"该有向边已存在,无需添加"<<endl;
return ;
}
else{
int u_index = -1, v_index = -1;
for(int i=0;i<G.vexnum;i++){
if(!u.compare(G.vexs[i])){
u_index = i;
uv ++;
if(uv==2) break;
}
else if(!v.compare(G.vexs[i])){
v_index = i;
uv ++;
if(uv==2) break;
}
}
G.arcs[u_index][v_index].adj = w;
}
}
删除一条边
把对应的边信息置0
void removeEdge(MGraph &G, string u, string v)
{
int u_index = -1, v_index = -1;
int uv = 0;
for(int i=0;i<G.vexnum;i++){
if(!u.compare(G.vexs[i])){
u_index = i;
uv ++;
if(uv==2) break;
}
else if(!v.compare(G.vexs[i])){
v_index = i;
uv ++;
if(uv==2) break;
}
}
if(uv!=2||G.arcs[u_index][v_index].adj==0){
return ;
}
else{
G.arcs[u_index][v_index].adj = 0;
}
}
显示出边信息
void drawGraph(MGraph &G)
{
for(int i=0;i<G.vexnum;i++){
cout<<G.vexs[i]<<" ";
}
cout<<endl;
for(int i=0;i<G.vexnum;i++){
for(int j=0;j<G.vexnum;j++){
cout<<G.arcs[i][j].adj<<" ";
}
cout<<endl;
}
cout<<endl;
}