有向图的十字链表存储表示 以及相关操作(包括增加弧、删除弧、删除顶点等)
2013-11-29 07:07
465 查看
十字链表表示特点
1.针对弧结点,增加入弧链表结构和出弧链表结构;
2.容易求得任意顶点的出度和入度,专用于有向图的操作;
3.结构实现比较复杂。
基本数据结构
1.弧的数据结构
typedef struct OLGArc
{
int tailvex;
int headvex;
struct OLGArc *hlink;
struct OLGArc *tlink;
}OLGArc;
2.顶点结构
typedef struct VexNode
{
char data;
OLGArc *firstin;
OLGArc *firstout;
}OLGVNode;
3.图的十字链表表示
typedef struct
{
OLGVNode xlist[MAX_VERTEX_NUM];
int vexnum;
int arcnum;
}OLGraph;
有向图的十字链表表示的相关操作
1.求图中某顶点在顶点数组中的下标
int LocateVex(OLGraph G,char x)
{
int i;
for(i=0;i<G.vexnum;++i)
if(G.xlist[i].data==x)
return i;
return -1;
}
2.创建有向图的十字链表存储表示
void CreateOLGraph(OLGraph &G)
{
int i,j,k;
char u,v;
//printf("input vexnum of G\n");
scanf("%d",&G.vexnum);
//printf("input arcnum of G\n");
scanf("%d",&G.arcnum);
printf("input value of each vertex of G\n"); // initial vertex array
getchar();
for(i=0;i<G.vexnum;++i)
{
scanf("%c",&G.xlist[i].data); //such as A B C D ,There is a blank between two vertex when you input data
if(i!=G.vexnum - 1)
getchar(); //eat the blank
G.xlist[i].firstin=NULL;
G.xlist[i].firstout=NULL;
}
printf("input the information of arc of G\n");
for(k=0;k<G.arcnum;++k)
{
scanf("%c %c",&u,&v);
getchar(); //eat the \n
i=LocateVex(G,u);
j=LocateVex(G,v);
OLGArc *p;
p=(OLGArc*)malloc(sizeof(OLGArc)); // apply a new save space
p->tailvex=i;
p->headvex=j;
p->hlink=G.xlist[j].firstin;
p->tlink=G.xlist[i].firstout;
G.xlist[i].firstout=p;
G.xlist[j].firstin=p;
}
}
3.十字链表存储表示的有向图的打印输出
void Display(OLGraph G)
{
int i,j,k;
OLGArc *p;
for(i=0;i<G.vexnum;++i)
printf("%c\t",G.xlist[i].data);
printf("\n");
for(i=0;i<G.vexnum;++i)
{
for(p=G.xlist[i].firstout;p!=NULL;p=p->tlink)
printf("%c--->%c\t",G.xlist[i].data,G.xlist[p->headvex].data);
}
printf("\n");
}
4.在有向图中插入一条新的弧
void InsertArc(OLGraph &G,char u,char v)
{
int i,j;
OLGArc *p;
i=LocateVex(G,u);
j=LocateVex(G,v);
p=(OLGArc*)malloc(sizeof(OLGArc));
p->headvex=j;
p->tailvex=i;
p->hlink=G.xlist[j].firstin;
p->tlink=G.xlist[i].firstout;
G.xlist[i].firstout=p;
G.xlist[j].firstin=p;
G.arcnum++;
}
5.在有向图中删除一条弧
void DeleteArc(OLGraph &G,char u,char v)
{
int i,j;
OLGArc *p,*q;
i=LocateVex(G,u);
j=LocateVex(G,v);
//修改u的出弧链表
if(G.xlist[i].firstout->headvex==j)
{
q=G.xlist[i].firstout;
G.xlist[i].firstout=q->tlink;
G.arcnum--;
}
else
{
for(p=G.xlist[i].firstout;p&&(p->tlink!=NULL)&&(p->tlink->headvex!=j);p=p->tlink);
if(p&&p->tlink) //之前没有加p->tlink!=NULL,若p->tlink==NULL,则q==NULL,q->tlink也就无意义了,同上差不多,会造成各种指针错误
{
q=p->tlink;
p->tlink=q->tlink;
G.arcnum--;
}
}
//修改v的入弧链表
if(G.xlist[j].firstin->tailvex==i)
{
q=G.xlist[j].firstin;
G.xlist[j].firstin=q->hlink;
free(q);
}
else
{
for(p=G.xlist[j].firstin;p&&(p->hlink)&&(p->hlink->tailvex!=i);p=p->hlink);
if(p&&p->hlink)
{
q=p->hlink;
p->hlink=q->hlink;
free(q);
}
}
}
6.删除有向图中的一个顶点
顶点删除分两步删除与v相关的弧
首先删除顶点v的所有入弧,这些弧结点分散于其他顶点的出弧链表中,同时也构成了顶点v的入弧链表。
在删除顶点v的入弧结点时不用维护顶点v入弧链表的连通性,但要维护该弧结点所在的其他顶点出弧链表的连通性。
void DeleteVex(OLGraph &G,char v)
{
int k=LocateVex(G,v);
int i,j;
OLGArc* p=NULL;
OLGArc* q=NULL;
for(j=0;j<G.vexnum;j++) //遍历所有结点的出弧链表,找到待删的弧结点(以v作为弧头结点的弧的结点),修改每个结点的要修改处的指针,保持目标结点被删除后仍保持原有的连通性
{
if(G.xlist[j].firstout==NULL) //该顶点没有出弧链表
continue;
else
{
if(G.xlist[j].firstout->headvex==k) //出弧链表的第一个结点恰好是要删除的结点
{
q=G.xlist[j].firstout;
G.xlist[j].firstout=q->tlink;
G.arcnum--;
}
else
{ //遍历链表找到要删除的弧的结点,其中(p->tlink!=NULL),之前没有加上,造成潜在隐患,若p->tlink==NULL,则p->tlink->headvex无效的引用
for(p=G.xlist[j].firstout;p&&(p->tlink!=NULL)&&(p->tlink->headvex!=k);p=p->tlink);
if(p&&p->tlink) //之前没有加p->tlink!=NULL,若p->tlink==NULL,则q==NULL,q->tlink也就无意义了,同上差不多,会造成各种指针错误
{
q=p->tlink;
p->tlink=q->tlink;
G.arcnum--;
}
}
}
}
//删除v的出弧链表和入弧链表
p=G.xlist[k].firstout;
while(p)
{
q=p;
p=p->tlink;
free(q);
}
p=G.xlist[k].firstin;
while(p)
{
q=p;
p=p->hlink;
free(q);
}
for(j=k+1;j<G.vexnum;j++) //数组前移
G.xlist[j-1]=G.xlist[j];
G.vexnum--; //顶点数减一
for(j=0;j<G.vexnum;j++)
{
for(p=G.xlist[j].firstout;p;p=p->tlink)
{
if(p->tailvex>k)
p->tailvex--;
if(p->headvex>k)
p->headvex--;
}
}
}
int main()
{
OLGraph G;
char u,v;
CreateOLGraph(G);
Display(G);
printf("input newly inserted arc\n");
scanf("%c %c",&u,&v);
InsertArc(G,u,v);
Display(G);
printf("input to be deleted vertex:\n");
getchar();
scanf("%c",&u);
DeleteVex(G,u);
Display(G);
printf("input to be deleted arc:\n");
getchar();
scanf("%c %c",&u,&v);
DeleteArc(G,u,v);
Display(G);
return 0;
}
//测试数据(创建一个有向图的十字链表存储表示) (测试数据对应于本文的第一幅图片)
/*
4
7
A B C D
A B
A C
C A
C D
D A
D B
D C
*/
1.针对弧结点,增加入弧链表结构和出弧链表结构;
2.容易求得任意顶点的出度和入度,专用于有向图的操作;
3.结构实现比较复杂。
基本数据结构
1.弧的数据结构
typedef struct OLGArc
{
int tailvex;
int headvex;
struct OLGArc *hlink;
struct OLGArc *tlink;
}OLGArc;
2.顶点结构
typedef struct VexNode
{
char data;
OLGArc *firstin;
OLGArc *firstout;
}OLGVNode;
3.图的十字链表表示
typedef struct
{
OLGVNode xlist[MAX_VERTEX_NUM];
int vexnum;
int arcnum;
}OLGraph;
有向图的十字链表表示的相关操作
1.求图中某顶点在顶点数组中的下标
int LocateVex(OLGraph G,char x)
{
int i;
for(i=0;i<G.vexnum;++i)
if(G.xlist[i].data==x)
return i;
return -1;
}
2.创建有向图的十字链表存储表示
void CreateOLGraph(OLGraph &G)
{
int i,j,k;
char u,v;
//printf("input vexnum of G\n");
scanf("%d",&G.vexnum);
//printf("input arcnum of G\n");
scanf("%d",&G.arcnum);
printf("input value of each vertex of G\n"); // initial vertex array
getchar();
for(i=0;i<G.vexnum;++i)
{
scanf("%c",&G.xlist[i].data); //such as A B C D ,There is a blank between two vertex when you input data
if(i!=G.vexnum - 1)
getchar(); //eat the blank
G.xlist[i].firstin=NULL;
G.xlist[i].firstout=NULL;
}
printf("input the information of arc of G\n");
for(k=0;k<G.arcnum;++k)
{
scanf("%c %c",&u,&v);
getchar(); //eat the \n
i=LocateVex(G,u);
j=LocateVex(G,v);
OLGArc *p;
p=(OLGArc*)malloc(sizeof(OLGArc)); // apply a new save space
p->tailvex=i;
p->headvex=j;
p->hlink=G.xlist[j].firstin;
p->tlink=G.xlist[i].firstout;
G.xlist[i].firstout=p;
G.xlist[j].firstin=p;
}
}
3.十字链表存储表示的有向图的打印输出
void Display(OLGraph G)
{
int i,j,k;
OLGArc *p;
for(i=0;i<G.vexnum;++i)
printf("%c\t",G.xlist[i].data);
printf("\n");
for(i=0;i<G.vexnum;++i)
{
for(p=G.xlist[i].firstout;p!=NULL;p=p->tlink)
printf("%c--->%c\t",G.xlist[i].data,G.xlist[p->headvex].data);
}
printf("\n");
}
4.在有向图中插入一条新的弧
void InsertArc(OLGraph &G,char u,char v)
{
int i,j;
OLGArc *p;
i=LocateVex(G,u);
j=LocateVex(G,v);
p=(OLGArc*)malloc(sizeof(OLGArc));
p->headvex=j;
p->tailvex=i;
p->hlink=G.xlist[j].firstin;
p->tlink=G.xlist[i].firstout;
G.xlist[i].firstout=p;
G.xlist[j].firstin=p;
G.arcnum++;
}
5.在有向图中删除一条弧
void DeleteArc(OLGraph &G,char u,char v)
{
int i,j;
OLGArc *p,*q;
i=LocateVex(G,u);
j=LocateVex(G,v);
//修改u的出弧链表
if(G.xlist[i].firstout->headvex==j)
{
q=G.xlist[i].firstout;
G.xlist[i].firstout=q->tlink;
G.arcnum--;
}
else
{
for(p=G.xlist[i].firstout;p&&(p->tlink!=NULL)&&(p->tlink->headvex!=j);p=p->tlink);
if(p&&p->tlink) //之前没有加p->tlink!=NULL,若p->tlink==NULL,则q==NULL,q->tlink也就无意义了,同上差不多,会造成各种指针错误
{
q=p->tlink;
p->tlink=q->tlink;
G.arcnum--;
}
}
//修改v的入弧链表
if(G.xlist[j].firstin->tailvex==i)
{
q=G.xlist[j].firstin;
G.xlist[j].firstin=q->hlink;
free(q);
}
else
{
for(p=G.xlist[j].firstin;p&&(p->hlink)&&(p->hlink->tailvex!=i);p=p->hlink);
if(p&&p->hlink)
{
q=p->hlink;
p->hlink=q->hlink;
free(q);
}
}
}
6.删除有向图中的一个顶点
顶点删除分两步删除与v相关的弧
首先删除顶点v的所有入弧,这些弧结点分散于其他顶点的出弧链表中,同时也构成了顶点v的入弧链表。
在删除顶点v的入弧结点时不用维护顶点v入弧链表的连通性,但要维护该弧结点所在的其他顶点出弧链表的连通性。
void DeleteVex(OLGraph &G,char v)
{
int k=LocateVex(G,v);
int i,j;
OLGArc* p=NULL;
OLGArc* q=NULL;
for(j=0;j<G.vexnum;j++) //遍历所有结点的出弧链表,找到待删的弧结点(以v作为弧头结点的弧的结点),修改每个结点的要修改处的指针,保持目标结点被删除后仍保持原有的连通性
{
if(G.xlist[j].firstout==NULL) //该顶点没有出弧链表
continue;
else
{
if(G.xlist[j].firstout->headvex==k) //出弧链表的第一个结点恰好是要删除的结点
{
q=G.xlist[j].firstout;
G.xlist[j].firstout=q->tlink;
G.arcnum--;
}
else
{ //遍历链表找到要删除的弧的结点,其中(p->tlink!=NULL),之前没有加上,造成潜在隐患,若p->tlink==NULL,则p->tlink->headvex无效的引用
for(p=G.xlist[j].firstout;p&&(p->tlink!=NULL)&&(p->tlink->headvex!=k);p=p->tlink);
if(p&&p->tlink) //之前没有加p->tlink!=NULL,若p->tlink==NULL,则q==NULL,q->tlink也就无意义了,同上差不多,会造成各种指针错误
{
q=p->tlink;
p->tlink=q->tlink;
G.arcnum--;
}
}
}
}
//删除v的出弧链表和入弧链表
p=G.xlist[k].firstout;
while(p)
{
q=p;
p=p->tlink;
free(q);
}
p=G.xlist[k].firstin;
while(p)
{
q=p;
p=p->hlink;
free(q);
}
for(j=k+1;j<G.vexnum;j++) //数组前移
G.xlist[j-1]=G.xlist[j];
G.vexnum--; //顶点数减一
for(j=0;j<G.vexnum;j++)
{
for(p=G.xlist[j].firstout;p;p=p->tlink)
{
if(p->tailvex>k)
p->tailvex--;
if(p->headvex>k)
p->headvex--;
}
}
}
int main()
{
OLGraph G;
char u,v;
CreateOLGraph(G);
Display(G);
printf("input newly inserted arc\n");
scanf("%c %c",&u,&v);
InsertArc(G,u,v);
Display(G);
printf("input to be deleted vertex:\n");
getchar();
scanf("%c",&u);
DeleteVex(G,u);
Display(G);
printf("input to be deleted arc:\n");
getchar();
scanf("%c %c",&u,&v);
DeleteArc(G,u,v);
Display(G);
return 0;
}
//测试数据(创建一个有向图的十字链表存储表示) (测试数据对应于本文的第一幅图片)
/*
4
7
A B C D
A B
A C
C A
C D
D A
D B
D C
*/
相关文章推荐
- 有向图的十字链表存储表示 以及相关操作(包括增加弧、删除弧、删除顶点等)
- 有向图的十字链表存储以及相关操作
- Oracle的列操作(增加列,修改列,删除列),包括操作多列
- jquery操作——事件相关知识(增加、删除、查看、编辑等)
- FIle 文件操作,包括文件的复制、删除以及zip和rar格式的解压操作
- Oracle-1:的列操作(增加列,修改列,删除列),包括操作多列
- [网络收集]DataList的相关操作实例的前台代码,如:分页、修改、删除、增加等
- Oracle的列操作(增加列,修改列,删除列),包括操作多列
- Oracle的列操作(增加列,修改列,删除列),包括操作多列
- Oracle的列操作(增加列,修改列,删除列),包括操作多列
- mysql增加和删除索引的相关操作
- Oracle的列操作(增加列,修改列,删除列),包括操作多列
- 定义元素类型为int、元素个数不受限制的集合类Set, 包括:<=(包含于)、==(相等)、!=(不等)、 |(并集)、 &(交集)、-(差集)、+=(增加元素)、-=(删除元素)等操作
- 针对Oracle表 列字段的增加、删除、修改以及重命名操作sql
- 线性表的存储以及相关操作实现
- net8:简易的文件磁盘管理操作二(包括文件以及文件夹的编辑创建删除移动拷贝重命名等)
- Java连接redis集群操作存储、删除以及获取值
- 使用JAVA代码来模拟线性链表的相关操作(增加,删除,插入及查找等)
- 串的堆分配存储表示以及相关操作 C语言版
- [置顶] 【数据结构】平衡二叉树的构建以及增加删除操作