在无向图的邻接表中可以看到,每一条边(vi,vj)在邻接表中有两个边结点:一个在顶点vi的边链表中,表示(vi,vj);一个在顶点vj的边链表中,表示(vj,vi)。
在较复杂的问题中,有时需要给被处理的边加标记(如访问标志或删除标志等),若用邻接表表示,则需要同时给表示某一条边的两个边结点加标记,而这两个结点又不在同一个边链表中,所以处理会很不方便。若改用邻接多重表作为无向图的存储表示,则可简化上述问题的处理。
对图中的每一个顶点用一个顶点结点表示,它有两个域组成,其中:
data域存储有关顶点的信息;
firstarc域是链接指针,指向第一条依附于该顶点的边。
所有的顶点结点组成一个顺序表。
template <class ElemType ,class WeightType>
class MultiAdjListNetworkVex
{
public:
ElemType data;
MultiAdjListNetworkArc<WeightType> *firstarc;
MultiAdjListNetworkVex()
{
firstarc = NULL;
}
MultiAdjListNetworkVex(ElemType val, MultiAdjListNetworkArc<WeightType>* adj = NULL)
{
data = val;
firstarc = adj;
}
};
在无向图的邻接多重表中,图的每一条边用一个边结点表示,它由六个域组成,其中:
tag是标记域,标记该边是否被处理或被搜索过;
weight为边的信息域,用于存储边的权值;adjvexl和adjvex2是顶点域,表示该边所依附的两个顶点在图中的序号;
nextarcl1域是链接指针,指向下一条依附于顶点adjvexl的边;
nextarc2也是链接指针,指向下一条依附于顶点adjvex2的边。
template <class WeightType>
class MultiAdjListNetworkArc
{
public:
int mark; //标记该边是否被搜索或处理过
WeightType weight; //边的权重
int adjVex1; //边的一个顶点
MultiAdjListNetworkArc<WeightType>* nextarc1; //指向下一条依附于adjvex1的边,eg:1-2-->1-3-->5-1
int adjVex2;
MultiAdjListNetworkArc<WeightType>* nextarc2;
MultiAdjListNetworkArc()
{
adjVex1= -1;
adjVex2= -1;
}
MultiAdjListNetworkArc(int v1, int v2, WeightType w, MultiAdjListNetworkArc<WeightType>* next1 = NULL,MultiAdjListNetworkArc<WeightType>* next2 = NULL)
{
adjVex1 = v1; adjVex2 = v2;
weight = w;
nextarc1 = next1; nextarc2=next2;
mark = 0; //0表示未被搜索,1表示被搜索过
}
1.类定义
template <class ElemType,class WeightType>
class MultiAdjListNetwork
{
protected:
int vexNum, vexMaxNum, arcNum;
MultiAdjListNetworkVex<ElemType, WeightType>* vexTable;
int* tag;
WeightType infinity;
public:
MultiAdjListNetwork(ElemType es[], int vertexNum,int vertexMaxNum= DEFAULT_SIZE, WeightType infinit = (WeightType)DEFAULT_INFINITY);
MultiAdjListNetwork(int vertexMaxNum = DEFAULT_SIZE, WeightType infinit = (WeightType)DEFAULT_INFINITY);
void Clear();
bool IsEmpty()
{
return vexNum == 0;
}
int GetArcNum()const
{
return arcNum;
}
int GetvexNum()const
{
return vexNum;
}
int FirstAdjVex(int v)const;
int NextAdjVex(int v1, int v2)const;
MultiAdjListNetworkArc<WeightType>* NextArc(int v1,MultiAdjListNetworkArc<WeightType>*p)const;
MultiAdjListNetworkArc<WeightType>* LastArc(int v1,MultiAdjListNetworkArc<WeightType>*p)const;
void InsertVex(const ElemType& d);
void InsertArc(int v1, int v2, WeightType w);
void DeleteVex(const ElemType& d);
void DeleteArc(int v1, int v2);
MultiAdjListNetwork(const MultiAdjListNetwork<ElemType, WeightType>* copy);
MultiAdjListNetwork<ElemType, WeightType> &operator=(const MultiAdjListNetwork<ElemType, WeightType>& copy);
///深度优先遍历
void DFS1(const int v);
void DFS1Traverse();
void DFS2();
int GetAdjVex(int head,int pre);//从顶点v出发的一个顶点u,返回v通往的下一个顶点;如果没有其它分支或者已经是最后一个连通点,返回-1;如果要取第一个顶点传入-1
void DFS3();
void BFS();
void Show();
};
2.函数的实现
研讨题,能够运行,但是代码不一定是最优的。
#include
#include
template <class ElemType,class WeightType>
MultiAdjListNetwork<ElemType,WeightType>::MultiAdjListNetwork(ElemType es[],int vertexNum,int vertexMaxNum,WeightType infinit)
{
if(vertexMaxNum < 0)
throw Error("允许的顶点最大数目不能为负!");
if (vertexMaxNum < vertexNum)
throw Error("顶点数目不能大于允许的顶点最大数目!");
vexNum = vertexNum;
vexMaxNum = vertexMaxNum;
arcNum = 0;
infinity = infinit;
tag = new int[vexMaxNum];
vexTable = new MultiAdjListNetworkVex<ElemType, WeightType>[vexMaxNum];
for (int v = 0; v < vexNum; v++)
{
tag[v] = 0;
vexTable[v].data = es[v];
vexTable[v].firstarc = NULL;
}
}
template <class ElemType,class WeightType>
MultiAdjListNetwork<ElemType,WeightType>::MultiAdjListNetwork(int vertexMaxNum, WeightType infinit)
{
if (vertexMaxNum < 0)
throw Error("允许的顶点最大数目不能为负!");
vexNum = 0;
vexMaxNum = vertexMaxNum;
arcNum = 0;
infinity = infinit;
tag = new int[vexMaxNum];
vexTable = new MultiAdjListNetworkVex<ElemType, WeightType>[vexMaxNum];
}
template<class ElemType, class WeightType>
int MultiAdjListNetwork<ElemType, WeightType>::FirstAdjVex(int v)const
{
if (v < 0 || v >= vexNum)
throw Error("v不合法!");
if (vexTable[v].firstarc == NULL)
return -1;
else
return vexTable[v].firstarc->adjVex1;
}
template<class ElemType, class WeightType>
int MultiAdjListNetwork<ElemType, WeightType>::NextAdjVex(int v1, int v2)const
{
MultiAdjListNetworkArc<WeightType>* p;
if (v1 < 0 || v1 >= vexNum)
throw Error("v1不合法!");
if (v2 < 0 || v2 >= vexNum)
throw Error("v2不合法!");
if (v1 == v2)
throw Error("v1不能等于v2!");
p = vexTable[v1].firstarc;
while (p != NULL && p->adjVex1 != v2 && p->adjVex2 != v2)
p = p->nextarc;
if (p == NULL || p->nextarc == NULL)
return -1; //不存在下一个邻接点
else if(p->adjVex1==v2)
return (p->nextarc2->adjVex1==v1?p->nextarc2->adjVex2:p->nextarc2->adjVex1);
else
return (p->nextarc1->adjVex1==v1?p->nextarc1->adjVex2:p->nextarc1->adjVex1);
}
template<class ElemType, class WeightType>
void MultiAdjListNetwork<ElemType, WeightType>::Clear()
{
if (IsEmpty()) return;
int n = vexNum;
for (int u = 0; u < n ; u++)
DeleteVex(vexTable[0].data);
return;
}
template<class ElemType, class WeightType>
MultiAdjListNetwork<ElemType, WeightType>::~MultiAdjListNetwork()
{
Clear();
}
template<class ElemType, class WeightType>
MultiAdjListNetwork<ElemType, WeightType>::MultiAdjListNetwork(const MultiAdjListNetwork<ElemType, WeightType>* copy)
{
vexMaxNum = copy.vexMaxNum;
vexNum = copy.vexNum;
vexTable = new MultiAdjListNetworkVex<ElemType,WeightType>[vexMaxNum];
arcNum = 0;
infinity = copy.infinity;
tag = new int[vexMaxNum];
for (int v = 0; v < vexNum; v++)
{
tag[v] = 0;
vexTable[v].data = copy.vexTable[v].data;
vexTable[v].firstarc = NULL;
}
MultiAdjListNetworkArc<WeightType>* p;
for (int u = 0; u < vexNum; u++)
{
p = copy.vexTable[u].firstarc;
while (p != NULL)
{
InsertArc(p->adjVex1, p->adjVex2, p->weight);
p=NextArc(u,p);
}
}
}
template<class ElemType, class WeightType> MultiAdjListNetwork<ElemType, WeightType>&
MultiAdjListNetwork<ElemType, WeightType>::operator=(const MultiAdjListNetwork<ElemType, WeightType>& copy)
{
if (this == ©) return *this;
Clear();
vexMaxNum = copy.vexMaxNum;
vexNum = copy.vexNum;
vexTable = new MultiAdjListNetworkVex<ElemType,WeightType>[vexMaxNum];
arcNum = 0;
infinity = copy.infinity;
tag = new int[vexMaxNum];
for (int v = 0; v < vexNum; v++)
{
tag[v] = 0;
vexTable[v].data = copy.vexTable[v].data;
vexTable[v].firstarc = NULL;
}
MultiAdjListNetworkArc<WeightType>* p;
for (int u = 0; u < vexNum; u++)
{
p = copy.vexTable[u].firstarc;
while (p != NULL)
{
InsertArc(p->adjVex1, p->adjVex2, p->weight);
p=NextArc(u,p);
}
}
return *this;
}
template<class ElemType, class WeightType> MultiAdjListNetworkArc<WeightType>*
MultiAdjListNetwork<ElemType, WeightType>::NextArc(int v1,MultiAdjListNetworkArc<WeightType>*p)const
{
if(p==NULL) return NULL;
if(p->adjVex1==v1)
return p->nextarc1;
else
return p->nextarc2;
}
template<class ElemType, class WeightType> MultiAdjListNetworkArc<WeightType>*
MultiAdjListNetwork<ElemType, WeightType>::LastArc(int v1,MultiAdjListNetworkArc<WeightType>*p)const
{
if(p==NULL)return NULL;
MultiAdjListNetworkArc<WeightType> *q=vexTable[v1].firstarc;
if(q==p)
return NULL;
while(q)
{
if(q->nextarc1==p ||q->nextarc2==p)
break;
q=NextArc(v1,q);
}
return q;
}
template<class ElemType, class WeightType>
void MultiAdjListNetwork<ElemType, WeightType>::InsertVex(const ElemType& d)
{
if (vexNum == vexMaxNum)
throw Error("图的顶点数不能超过允许的最大数!");
vexTable[vexNum].data = d;
vexTable[vexNum].firstarc = NULL;
tag[vexNum] = 0;
vexNum++;
}
template<class ElemType, class WeightType>
void MultiAdjListNetwork<ElemType, WeightType>::InsertArc(int v1, int v2, WeightType w)
{
MultiAdjListNetworkArc<WeightType>* p,*q;
if (v1 < 0 || v1 >= vexNum)
throw Error("v1不合法!");
if (v2 < 0 || v2 >= vexNum)
throw Error("v2不合法!");
if (v1 == v2)
throw Error("v1不能等于v2!");
if (w == infinity)
throw Error("w不能为无穷大!");
p = vexTable[v1].firstarc;
while(p)
{
if(p->adjVex1==v2||p->adjVex2==v2)//边已经在顶点的邻接边中
{
if(p->weight!=w)
p->weight=w;
return;
}
p=NextArc(v1,p);
}
p = vexTable[v1].firstarc;
q = vexTable[v2].firstarc;
vexTable[v1].firstarc = new MultiAdjListNetworkArc<WeightType>(v1,v2, w, p,q);//头插法
vexTable[v2].firstarc =vexTable[v1].firstarc;
arcNum++;
}
template<class ElemType, class WeightType>
void MultiAdjListNetwork<ElemType, WeightType>::DeleteArc(int v1, int v2)
{
MultiAdjListNetworkArc<WeightType>* p, * q,*r;
if (v1 < 0 || v1 >= vexNum)
throw Error("v1不合法!");
if (v2 < 0 || v2 >= vexNum)
throw Error("v2不合法!");
if (v1 == v2)
throw Error("v1不能等于v2!");
p = vexTable[v1].firstarc;
while (p != NULL && p->adjVex2!= v2&&p->adjVex1!=v2)
{
q = p;
p = NextArc(v1,p);
}//找到要删除的边结点p及其前一结点q
if (p != NULL)//找到v1-v2的边
{
r=LastArc(v2,p);
if (vexTable[v1].firstarc == p)//第一条边,q此时为NULL
if(p->adjVex2==v2)
vexTable[v1].firstarc = p->nextarc1;
else vexTable[v1].firstarc=p->nextarc2;
else//不是第一条边
{
if(q->adjVex1==v1)
q->nextarc1 = NextArc(v1,p);
else
q->nextarc2=NextArc(v1,p);
}
if(r==NULL)
if(p->adjVex2==v2)
vexTable[v2].firstarc = p->nextarc2;
else vexTable[v2].firstarc=p->nextarc1;
else
{
if(r->adjVex2==v2)
r->nextarc2 = NextArc(v2,p);
else
r->nextarc1=NextArc(v2,p);
}
delete p;
arcNum--;
}
}
template<class ElemType, class WeightType> void
MultiAdjListNetwork<ElemType, WeightType>::DeleteVex(const ElemType& d)
{
int v;
MultiAdjListNetworkArc<WeightType>* p;
for (v = 0; v < vexNum; v++)//找到d对应顶点
if (vexTable[v].data == d)
break;
if(v==vexNum)
throw Error("图中不存在要删除的顶点!");
for (int u = 0; u < vexNum; u++)//删除与d相连的边
if (u != v)
{
DeleteArc(u, v);
}
vexTable[v].firstarc=NULL;
vexNum--;///将原来的vexTable[vexNum-1]即最后一个节点移动到原来v的位置
vexTable[v].data = vexTable[vexNum].data;
vexTable[v].firstarc = vexTable[vexNum].firstarc;
vexTable[vexNum].firstarc = NULL;
tag[v] = tag[vexNum];
//原来与最后一个顶点相连的边改为与v相连
for (int u = 0; u < vexNum; u++)
{
if (u != v)
{
p = vexTable[u].firstarc;
while (p)
{
if (p->adjVex1==vexNum)
p->adjVex1= v;
else if(p->adjVex2==vexNum)
p->adjVex2=v;
p = NextArc(u,p);
}
}
}
}
///深度优先遍历
template<class ElemType, class WeightType> void MultiAdjListNetwork<ElemType, WeightType>::DFS1(const int v)
{
tag[v]=1;
cout<<setw(3)<<vexTable[v].data;
MultiAdjListNetworkArc<WeightType> *p;
p=vexTable[v].firstarc;
while(p)
{
if(tag[p->adjVex1]==0)
DFS1(p->adjVex1);
else if(tag[p->adjVex2]==0)
DFS1(p->adjVex2);
p=NextArc(v,p);
}
}
template<class ElemType, class WeightType> void MultiAdjListNetwork<ElemType, WeightType>::DFS1Traverse()
{
for(int i=0; i<vexNum; i++)
tag[i]=0;
for(int v=0; v<vexNum; v++)
{
if(tag[v]==0)
DFS1(v);
}
}
template<class ElemType, class WeightType> void MultiAdjListNetwork<ElemType, WeightType>::DFS2()
{
stack<int> s;
int tmp;
MultiAdjListNetworkArc<WeightType> *p,*q;
for(int i=0; i<vexNum; i++)
tag[i]=0;
for(int i=0; i<vexNum; i++)
{
tmp=i;
while(tag[tmp]==0||!s.empty())
{
p=vexTable[tmp].firstarc;
while(tag[tmp]==0)
{
s.push(tmp);
cout<<setw(3)<<vexTable[tmp].data;
tag[tmp]=1;
p=vexTable[tmp].firstarc;
if(p==NULL) break;///该顶点没有边,连通分支结束(1个点)先出栈再跳出循环进入for
tmp=(p->adjVex1==tmp?p->adjVex2:p->adjVex1);
//cout<<" 1st tmp="<
}
if(!s.empty())
{
tmp=s.top();
s.pop();
q=vexTable[tmp].firstarc;
int t=tmp;
while(q&&tag[tmp]!=0)
{
tmp=(q->adjVex1==t?q->adjVex2:q->adjVex1);
//cout<<" 2nd tmp="<
q=NextArc(t,q);
}
if(tag[tmp]==0)
s.push(t);
///1、对应上面连通分支只有1个点的情况
///2、t上的点都被访问过,此时tmp是t相连的最后一个点,用于跳过上面while,再次进行出栈
///tmp要么等于找到的第一个未访问节点,
///要么等于与t相连最后一个点(已被访问过)
///当连通图只有一个节点时,这时tmp=这个已访问的孤立节点
}
}
}
}
//从顶点v出发的一个顶点u,返回v通往的下一个顶点;如果没有其它分支或者已经是最后一个连通点,返回-1;如果要取第一个顶点传入-1
template<class ElemType, class WeightType> int
MultiAdjListNetwork<ElemType, WeightType>::GetAdjVex(int head,int pre)
{
if(head==pre)
return -1;
MultiAdjListNetworkArc<WeightType> *p;
p=vexTable[head].firstarc;
if(pre==-1&&p!=NULL)
return p->adjVex1==head?p->adjVex2:p->adjVex1;
//pre!=-1&&p!=NULL
while(p!=NULL)
{
if(p->adjVex1==head && p->adjVex2!=pre)
p=p->nextarc1;
else if(p->adjVex2==head && p->adjVex1!=pre)
p=p->nextarc2;
else if(p->adjVex1==head && p->adjVex2==pre)
{
p=p->nextarc1;
break;
}
else if(p->adjVex2==head && p->adjVex1==pre)
{
p=p->nextarc2;
break;
}
}
if(p!=NULL)
{
return p->adjVex1==head?p->adjVex2:p->adjVex1;
}
else
return -1;
}
template<class ElemType, class WeightType> void MultiAdjListNetwork<ElemType, WeightType>::DFS3()
{
stack<int> s;
int p,cur,pre;
//MultiAdjListNetworkArc *p,*q;
for(int i=0; i<vexNum; i++) tag[i]=0;//初始化
for(int i=0; i<vexNum; i++)
{
cur=i;pre=-1;
while(tag[cur]==0||!s.empty())
{
while(tag[cur]==0)
{
cout<<vexTable[cur].data<<" ";
s.push(cur);
tag[cur]=1;
//初次访问,标记入栈
p=GetAdjVex(cur,pre);//p是cur的连通顶点
if(p==-1)
{
pre=cur;s.pop();
break;
}
else
{
pre=cur;
cur=p;
}
}
while(!s.empty())
{
cur=s.top();
p=GetAdjVex(cur,pre);
if(tag[p]==0)
{
pre=cur;
cur=p;
break;
}
else
{
pre=s.top();
s.pop();
}
}
}
}
}
template<class ElemType, class WeightType> void MultiAdjListNetwork<ElemType, WeightType>::BFS()
{
for(int i=0; i<vexNum; i++)
tag[i]=0;
queue<int> q;
int tmp,t;
MultiAdjListNetworkArc<WeightType> *p;
for(int i=0; i<vexNum; i++)
{
if(tag[i]==0)
{
tag[i]=1;
q.push(i);
cout<<setw(3)<<vexTable[i].data;
}
while(!q.empty())
{
tmp=q.front();
q.pop();
p=vexTable[tmp].firstarc;
while(p!=NULL)
{
t=(p->adjVex1==tmp?p->adjVex2:p->adjVex1);
if(tag[t]==0)
{
cout<<setw(3)<<vexTable[t].data;
tag[t]=1;
q.push(t);
}
p=NextArc(tmp,p);
}
}
}
}
template<class ElemType, class WeightType> void MultiAdjListNetwork<ElemType, WeightType>::Show()
{
MultiAdjListNetworkArc<WeightType> *p;
cout << "无向图有" << vexNum << "个点,分别为:";
for (int i = 0; i < vexNum; i++)
cout << vexTable[i].data << " ";
cout << endl;
cout << "无向图有" << arcNum << "条边"<<endl;
for (int i = 0; i < vexNum; i++)
{
cout<<"和" << vexTable[i].data << "有关的边:";
p = vexTable[i].firstarc;
while (p != NULL)
{
cout << vexTable[p->adjVex1].data << "<--"<<p->weight<<"-->" << vexTable[p->adjVex2].data << ",";
p=NextArc(i,p);
}
cout << endl;
}
}
邻接表链接
在无向图的邻接多重表中,所需存储空间与表示无向图的邻接表相同。
在无向图的应用中,如果更加关注图的顶点,那么邻接表是不错的选择,但如果我们更关注边的操作,比如对已访问过的边做标记,删除某一条边等操作,那就意味着需要找到这条边的两个边表结点进行操作,若要删除某条边,需要对邻接表结构中相关的两个结点进行删除,显然这是比较繁琐的。
为了提高在无向图中操作顶点的效率,又有了邻接多重表的存储结构。邻接多重表与邻接表的区别在于,同一条边,在邻接多重表中要用两个结点表示,而在邻接表中只需要一个结点。此外,邻接多重表中增加了标志域用以标记该条边是否被搜索过,避免了同一条边的重复搜索。
至此,邻接多重表完毕#