对于任意一个非空广义表来说,都是由两部分组成:表头和表尾。反之,只要确定的一个广义表的表头和表尾,那么这个广义表就可以唯一确定下来。
复制一个广义表,也是不断的复制表头和表尾的过程。如果表头或者表尾同样是一个广义表,依旧复制其表头和表尾。
所以,复制广义表的过程,其实就是不断的递归,复制广义表中表头和表尾的过程。
递归的出口有两个:
如果当前遍历的数据元素为空表,则直接返回空表。
如果当前遍历的数据元素为该表的一个原子,那么直接复制,返回即可。
还拿广义表 c 为例:
图1 广义表 c 的结构示意图
代码实现:
#include#include typedef struct glnode{ int tag;//标志域 union{ char atom;//原子结点的值域 struct{ struct glnode * hp,*tp; }ptr;//子表结点的指针域,hp指向表头;tp指向表尾 }; }*glist,gnode; glist creatglist(glist c){ //广义表c c=(glist)malloc(sizeof(gnode)); c->tag=1; //表头原子‘a’ c->ptr.hp=(glist)malloc(sizeof(gnode)); c->ptr.hp->tag=0; c->ptr.hp->atom='a'; //表尾子表(b,c,d),是一个整体 c->ptr.tp=(glist)malloc(sizeof(gnode)); c->ptr.tp->tag=1; c->ptr.tp->ptr.hp=(glist)malloc(sizeof(gnode)); c->ptr.tp->ptr.tp=null; //开始存放下一个数据元素(b,c,d),表头为‘b’,表尾为(c,d) c->ptr.tp->ptr.hp->tag=1; c->ptr.tp->ptr.hp->ptr.hp=(glist)malloc(sizeof(gnode)); c->ptr.tp->ptr.hp->ptr.hp->tag=0; c->ptr.tp->ptr.hp->ptr.hp->atom='b'; c->ptr.tp->ptr.hp->ptr.tp=(glist)malloc(sizeof(gnode)); //存放子表(c,d),表头为c,表尾为d c->ptr.tp->ptr.hp->ptr.tp->tag=1; c->ptr.tp->ptr.hp->ptr.tp->ptr.hp=(glist)malloc(sizeof(gnode)); c->ptr.tp->ptr.hp->ptr.tp->ptr.hp->tag=0; c->ptr.tp->ptr.hp->ptr.tp->ptr.hp->atom='c'; c->ptr.tp->ptr.hp->ptr.tp->ptr.tp=(glist)malloc(sizeof(gnode)); //存放表尾d c->ptr.tp->ptr.hp->ptr.tp->ptr.tp->tag=1; c->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp=(glist)malloc(sizeof(gnode)); c->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp->tag=0; c->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp->atom='d'; c->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.tp=null; return c; } void copyglist(glist c, glist *t){ //如果c为空表,那么复制表直接为空表 if (!c) { *t=null; } else{ *t=(glist)malloc(sizeof(gnode));//c不是空表,给t申请内存空间 //申请失败,程序停止 if (!*t) { exit(0); } (*t)->tag=c->tag;//复制表c的tag值 //判断当前表元素是否为原子,如果是,直接复制 if (c->tag==0) { (*t)->atom=c->atom; }else{//运行到这,说明复制的是子表 copyglist(c->ptr.hp, &((*t)->ptr.hp));//复制表头 copyglist(c->ptr.tp, &((*t)->ptr.tp));//复制表尾 } } } int main(int argc, const char * argv[]) { glist c=null; c=creatglist(c); glist t=null; copyglist(c,&t); printf("%c",t->ptr.hp->atom); return 0; }
运行结果:
a
总结
在实现复制广义表的过程中,实现函数为:
void copyglist(glist c, glist *t);
其中,glist *t,等同于: struct glnode* *t,此为二级指针,不是一级指针。在主函数中,调用此函数时,传入的是指针 t 的地址,而不是 t 。
这里使用的是地址传递,而不是值传递。如果在这里使用值传递,会导致广义表 t 丢失结点,复制失败。