有向图的十字链表储存及相关算法
# include<iostream>
# include<stdlib.h>
# include<queue>
# include<cstring>
using namespace std;
const int N = 10050;
typedef struct Arcbox{
int tailvex,headvex;//弧尾和弧头的 位置(方向是弧尾能走到弧头)
struct Arcbox *hlink,*tlink;//相同弧头,相同弧尾的弧的链
}Arcbox;//存储边的信息
typedef struct{
int data;//数据域
Arcbox *firstin,*firstout;//指向该顶点的第一条入弧和第一条出弧
}Vexnode;//存储点的信息
typedef struct{
Vexnode xlist[N];//表头向量(数组)
int vexnum,arcnum;//有向图当前顶点数目和弧数
}OLGraph;
int Locatevex(OLGraph G,int u){
/*返回顶点u在有向图G中的位置(序号),不存在就返回-1*/
int i;
for(i = 1;i <= G.vexnum;++i)
{
if(G.xlist[i].data == u)
return i;
}
return -1;
}
bool CreatDG(OLGraph * G){
/*建图*/
Arcbox * p;
printf("请输入有向图的顶点数,弧数");
cin>>G->vexnum>>G->arcnum;
cout<<"请输入有向图"<<G->vexnum<<"个顶点的数据"<<endl;
for(int i = 1;i <= G->vexnum;++i)
{
cin>>G->xlist[i].data;
G->xlist[i].firstin = NULL;//初始化入弧
G->xlist[i].firstout = NULL;//初始化出弧
}
cout<<"请输入"<<G->arcnum<<"条边的弧尾和弧头";
for(int i = 1;i <= G->arcnum;++i)
{
int v1,v2;
cin>>v1>>v2;
int j = Locatevex(*G,v1);//找到与v1值相同的点的下标
int k = Locatevex(*G,v2);//找到与v2值相同的点的下标
p = new Arcbox;//p指向一个新的边
p->tailvex = j;//新边的弧尾是j(v1)
p->headvex = k;//新边的弧头是k(v2)
p->hlink = G->xlist[k].firstin;
p->tlink = G->xlist[j].firstout;
G->xlist[k].firstin = G->xlist[j].firstout = p;
/*头插法*/
}
return true;
}
void DestroyGraph(OLGraph *G)
{
/*初始条件:存在图G*/
/*操作结果:摧毁有向图G*/
Arcbox *p,*q;
for(int i = 1;i <=G->vexnum;++i)
{
p = G->xlist[i].firstout;//指向该顶点的第一条出边
while(p)
{
q = p;
p = p->tlink;//指向该顶点的下一条出边
free(q);//释放出边
}
}
G->arcnum = G->vexnum = 0;
}
int * GetVex(OLGraph * G,int v)
{
if(v>=G->vexnum||v < 0) exit(-1);//循环中不要用,因为在图中如果调用到没有值得点会被终止程序,造成逻辑错误
return &G->xlist[v].data;//返回顶点v的值域地址
}
bool PutVex(OLGraph *G,int v,int val)
{
/*修改顶点v的值为val*/
int i = Locatevex(*G,v);
if(i < 0)//如果不存在点值为v的点
return false;//修改失败
G->xlist[i].data = val;
return true;
}
int FirstAdjvex(OLGraph G,int v)
{
/*返回值为v的顶点的第一个领接顶点的序号,若没有领接顶点则返回-1*/
int i;
Arcbox *p;
i = Locatevex(G,v);
p = G.xlist[i].firstout;
if(p)
return p->headvex;//指向该顶点的弧头
else
return -1;
}
int NextAdjvex(OLGraph G,int v,int w){
/*初始条件:有向图G存在,v是图G的顶点,w是v的领接点*/
/*操作结果:返回值为v的顶点领接点中,在w之后的下一个领接顶点的序号*/
/*若w是v的最后一个领接顶点,返回-1*/
Arcbox * p;
int i = Locatevex(G,v);
int j = Locatevex(G,w);
p = G.xlist[i].firstout;
while(p && p->headvex != j)
p = p->tlink;
if(p) /*w不是v的最后一个领接点*/
p = p->tlink;/*指向w的下一个领接点*/
if(p)/*w后是否存在下一个领接点*/
return p->headvex;/*有则输出*/
else return -1;
}
void Insertvex(OLGraph *G,int v)
{
/*在 图中增加新的顶点,不增加边*/
G->xlist[++G->vexnum].data = v;
G->xlist[G->vexnum].firstin = G->xlist[G->vexnum].firstout = NULL;
}
bool Deletevex(OLGraph *G,int v)
{
/*删除顶点v及其相关边*/
int j,k;
Arcbox *p,*q;
k = Locatevex(*G,v);//获取值为v的顶点下标
if(k < 0) return false;//若不存在值为v的顶点就返回删除失败
/*删除顶点v的出弧*/
for(j = 1;j <= G->vexnum;++j)
{
if(j == k) continue;//先不动顶点v
p = G->xlist[j].firstin;/*顶点v的出弧就是其他点的入弧*/
while(p)
if(p->tailvex == k && (p == G->xlist[j].firstin))/*待删节点为首节点,也就是说我们要删除的节点没有领接点*/
{
G->xlist[j].firstin = p->hlink;/*此时p->hlink为NULL*/
break;
}
else if (p->tailvex != k)//如果边p的弧尾不是v
{
q = p;//q储存上一条边的位置
p = p->hlink;//p指向下一条边
}
else
{
q->hlink = p->hlink;//上一条边的链指向下一条边的下一条边
break;
}
}
/*删除与顶点v有关的出弧*/
p = G->xlist[k].firstout;
while(p)
{
q = p->tlink;//q指向下一条出边
free(p);//释放当前边
G->arcnum--;//总边数减少
p = q;//p也指向下一条出边
}
/*删除顶点v的入弧*/
for(j = 1;j <= G->vexnum;++j)
{
if(j == k) continue;
p = G->xlist[j].firstout;/*顶点v的入弧就是其他顶点的出弧*/
while(p)
if(p->headvex == k &&p == G->xlist[j].firstout)//若p指向该顶点的第一条(它的弧头为v)出边且该顶点只有这一条出边
{
G->xlist[j].firstout = p->tlink;//让顶点j的出边指向NULL
break;
}
else if(p->headvex != k)//如果该出边弧头不是v
{
q = p;//q指向上一条出边
p = p->tlink;//p指向下一条出边
}
else
{
q->tlink = p->tlink;//上一条出边的链指向下一条出边的下一条出边
break;
}
}
/*删除与顶点v有关的入弧*/
p = G->xlist[k].firstin;
while(p)
{
q = p->hlink;
free(p);
G->arcnum--;
p = q;
}
/*改变顶点位于图中的位置(下标)*/
for(j = k+1;j <= G->vexnum;++j) G->xlist[j-1] = G->xlist[j];//所有顶点向前移一位
G->vexnum--;//减少总顶点数
for(j = 1;j <= G->vexnum;++j)
{
p = G->xlist[j].firstout;
while(p)
{
if(p->tailvex>k)
p->tailvex--;//顶点大小-1
if(p->headvex>k)
p->headvex--;//顶点大小-1
p = p->tlink;
}
}
return true;
}
bool InsertArc(OLGraph *G,int v,int w)
{
/*对图G中点v和点w加一条边<v,w>*/
int i = Locatevex(*G,v);
int j = Locatevex(*G,w);
Arcbox * p;
if(i<0 || j<0) return false;
p = new Arcbox;
p->tailvex = i;
p->headvex = j;
p->hlink = G->xlist[j].firstin;
p->tlink = G->xlist[i].firstout;/*头插法*/
G->xlist[j].firstin = G->xlist[i].firstout = p;
G->arcnum++;
return true;
}
bool DeleteArc(OLGraph * G,int v,int w)
{
/*删除边<v,w>*/
int i = Locatevex(*G,v);/*弧尾序号*/
int j = Locatevex(*G,w);/*弧头序号*/
Arcbox *p,*p2;
if(i<0||j<0 || i==j) return false;
p2 = G->xlist[i].firstout;//删除弧尾节点
if(p2&&p2->headvex == j) G->xlist[i].firstout = p2->tlink;//如果第一个领接边为待删除边
else
{
while(p2&&p2->headvex!=j)//向后找
{
p = p2;
p2 = p2->tlink;
}
if(p2)/*没到表尾*/
{
p->tlink = p2->tlink;
}
}
p2 = G->xlist[j].firstin;//处理入边
if(p2&&p2->tailvex == i) G->xlist[j].firstin = p2->hlink;
else
{
while(p2&&p2->tailvex!=i)
{
p = p2;
p2 = p2->hlink;
}
if(p2) p ->hlink = p2->hlink;
}
free(p2);/*释放边*/
G->arcnum--;//弧数减一
return true;
}
bool vis[N];//标记是否遍历过该点
void DFS(OLGraph G,int i)
{
Arcbox *p;
vis[i] = true;//标记当前结点已经来过
cout<<G.xlist[i].data<<" ";/*输出结点值域*/
p = G.xlist[i].firstout;/*p指向i的第一条出边*/
while(p && vis[p->headvex]) p = p->tlink;/*如果i存在出边且该出边的弧头已被遍历*/
if(p && !vis[p->headvex])/*如果p存在且当前p指向的边的弧头尚未被遍历*/
DFS(G,p->headvex); /*递归调用DFS*/
}
void dfsTraverse(OLGraph G)
{
for(int i = 1;i <= G.vexnum;++i) vis[i] = false;/*初始化所有结点为尚未被遍历*/
for(int i = 1;i <= G.vexnum;++i)
if(!vis[i] ) DFS(G,i);/*如果当前结点尚未被遍历,则调用DFS*/
cout<<endl;
}
void BFS(OLGraph G){
for(int i = 1;i <=G.vexnum;++i) vis[i] = false;/*初始化所有结点为尚未被遍历*/
queue<int> q;/*创建队列*/
for(int i =1;i <= G.vexnum;++i)
{
if(!vis[i])/*如果当前结点没被遍历*/
{
vis[i] = true;/*设为遍历过*/
cout<<G.xlist[i].data<<" ";/*输出结点信息*/
q.push(i);/*点i入队*/
while(!q.empty())/*队列非空*/
{
int top = q.front();/*top接收队头元素*/
int k = *GetVex(&G,top);/*k获取顶点top的值域*/
q.pop();/*队头出队*/
for(int w = FirstAdjvex(G,k);w != -1; w = NextAdjvex(G,k,G.xlist[w].data))/*遍历顶点top的所有出边*/
if(!vis[w])/*如果尚未被遍历*/
{
vis[w] = 1;/*设为被遍历过*/
cout<<G.xlist[w].data<<" ";/*输出值域*/
q.push(w); /*入队*/
}
}
}
}
cout<<endl;
}
int main()
{
int n;
OLGraph G;
int v1,v2;
CreatDG(&G);
dfsTraverse(G);
printf("清修改顶点的值,输入原值,新值:");
cin>>v1>>v2;
PutVex(&G,v1,v2);
printf("请插入新顶点,并输入顶点的值:");
cin>>v1;
Insertvex(&G,v1);
printf("请输入新顶点相关的弧,请输入弧数:");
cin>>n;
for(int i = 1;i <= n;++i)
{
printf("请输入另一顶点的值,另一顶点的方向(0:弧头,1:弧尾)");
int j;
cin>>v2>>j;
if(j)
InsertArc(&G,v2,v1);
else
InsertArc(&G,v1,v2);
}
dfsTraverse(G);
printf("删除一条弧,请输入待删除弧的弧尾 弧头:");
cin>>v1>>v2;
DeleteArc(&G,v1,v2);
dfsTraverse(G);
printf("删除顶点及其相关弧,请输入顶点的值:");
cin>>v1;
Deletevex(&G,v1);
dfsTraverse(G);
BFS(G);
return 0;
}

浙公网安备 33010602011771号