我是“计算机科学与技术”专业的一名在校本科生,这是我的第一篇博文,用词不当还请各位看官多多包涵。
这篇博文是关于西北工业大学NOJ数据结构习题中的“求广义表深度”的思路实现与调试心得,如有错误或纰漏欢迎各位大佬指正。
题目如下:
读题之后,第一反应是与之前做过的一道“表达式括号匹配”题目类似,似乎可以用“栈”的方法来解决,但题目明确要求要用广义表而且老师前两天也刚刚讲过关于广义表的递归运算,所以我决定使用递归来将数据存入广义表,再使用递归来计算出该广义表的深度。
构建广义表的思路是通过判断每次输入的字符来判断需要新生成什么样的节点,再通过上一节点信息来判断当前节点应连接在表的什么位置;计算广义表深度的思路是通过判断该节点的信息,计算出后面与下面所有节点深度最大一个,形成递归,最终返回改广义表的深度。
首先设计出节点的数据类型,“judge”用来判断此节点类型,1是“Data节点”,0是“Node节点”;“before”是指向上一个节点指针;“next”是指向右侧节点的指针;红框内是union型的数据,为“Data节点”时是存入的数据,为“Node节点”时是指向下面节点的指针。
由此可以将(a,(b,c))转变为所设计的广义表:同级的a与bc同行,同级的b与c同行,每个“Node节点”的down所在行的每一节点就是该括号内的所有数据,如下图:
而我计算深度的方法是不断将节点右侧和下方的深度计算出来,取其中最大的深度,如下图:
我的实现如下:
#include <stdio.h> #include <stdlib.h> struct Node { int judge; struct Node *before; struct Node *next; union { struct Node *down; char data; }; }; void createGeneralNode (struct Node *pre); void createGeneralList (struct Node *head); void run (); int getDepth (struct Node *node); int main() { run (); return 0; } void createGeneralNode (struct Node *pre) { char s,ss=0; struct Node *cur; if ((s=getchar())==',') { ss=s; s=getchar(); } if (s>='a'&&s<='z') { cur =(struct Node *)malloc (sizeof(struct Node)); if (ss==',') { pre->next=cur; } else { pre->down=cur; } cur->before=pre; cur->data=s; cur->next=NULL; cur->judge=1; createGeneralNode (cur); } else { if (s=='(') { cur =(struct Node *)malloc (sizeof(struct Node)); if (ss==',') { pre->next=cur; } else { pre->down=cur; } cur->before=pre; cur->down=NULL; cur->next=NULL; cur->judge=0; createGeneralNode (cur); } else { if (s==')') { while (pre->judge||pre->next) { pre=pre->before; } createGeneralNode (pre); } } } } void createGeneralList (struct Node *head) { head->judge=0; head->down=NULL; head->next=NULL; head->before=NULL; createGeneralNode(head); } void run () { struct Node head; int depth; createGeneralList(&head); depth=getDepth(head.down); printf ("%d\n%d",depth,depth); } int getDepth (struct Node *node) { int max=0,depth; struct Node *p; for (p=node->next;p;p=p->next) { if (p->judge) { depth=0; } else { if (p->down) { depth=getDepth(p->down)+1; } else { depth=1; } } max=depth>max?depth:max; } if (node->judge) { depth=0; } else { if (node->down) { depth=getDepth(node->down)+1; } else { depth=1; } } return max=depth>max?depth:max; }其函数调用关系如下:
以下是各函数注释代码:
void run () { struct Node head; int depth; createGeneralList(&head); //创建广义表并输入数据 depth=getDepth(head.down); //获得广义表深度 printf ("%d\n%d",depth,depth); //输出 }
void createGeneralList (struct Node *head) { head->judge=0; //初始化 head->down=NULL; //初始化 head->next=NULL; //初始化 head->before=NULL; //初始化 createGeneralNode(head); //创建节点 }
void createGeneralNode (struct Node *pre)//输入值为上一个节点地址 { char s,ss=0; struct Node *cur; if ((s=getchar())==',')//若输入为",",记录 { ss=s; s=getchar(); } if (s>='a'&&s<='z') { cur =(struct Node *)malloc (sizeof(struct Node)); if (ss==',') //如果与上一个节点同行 { pre->next=cur; } else //如果与上一个节点不同行 { pre->down=cur; } cur->before=pre; //该Date节点赋值 cur->data=s; cur->next=NULL; cur->judge=1; createGeneralNode (cur);//递归,重新创建节点 } else { if (s=='(') { cur =(struct Node *)malloc (sizeof(struct Node)); if (ss==',') //如果与上一个节点同行 { pre->next=cur; } else //如果不同行 { pre->down=cur; } cur->before=pre; //Node节点赋值 cur->down=NULL; cur->next=NULL; cur->judge=0; createGeneralNode (cur);//重新创建节点 } else { if (s==')') { while (pre->judge||pre->next)//寻找前面第一个右侧为空的Node节点 { pre=pre->before; } createGeneralNode (pre);//重新创建节点 } } } }
int getDepth (struct Node *node) { int max=0,depth; struct Node *p; for (p=node->next;p;p=p->next) //遍历节点右侧部分,寻找其中最大深度 { if (p->judge) { depth=0; } else { if (p->down) { depth=getDepth(p->down)+1; } else { depth=1; } } max=depth>max?depth:max; } if (node->judge) //遍历下方节点,寻找其中最大深度 { depth=0; } else { if (node->down) { depth=getDepth(node->down)+1; } else { depth=1; } } return max=depth>max?depth:max;//返回两侧深度较大的值 }
输入函数我重写了两次才完成,都是因为判断条件不完善导致无法得到正确的广义表,下次在设计时需要考虑周全,避免无意义的返工。
测深度的方法想了好久,也参考了老师的方法(其实是没看懂。。。),主要原因还是对递归的理解不够透彻,无法直接想出所需的递归算法。
第一次写的博文,写了很长时间,已经快三点了。。。下次我一定尽量在白天写,希望自己能坚持下来。