int height(NODE* head){
if(!head->link)return 0;//空表深度为0
int ret=1;//
NODE* p=head->link;
while(p){//遍历链表的每一个结点,结点的最大深度加1即为链表的最大深度
if(p->tag==1){//当结点是广义表时
int h=height(p->dd.dlink)+1;//计算深度
ret=h>ret?h:ret;//更新最大深度
}
p=p->link;
}
return ret;
}
//完整代码,供测试使用
#include<bits/stdc++.h>
using namespace std;
struct node
{
int tag; // 当 tag==0时 第二个字段为 data 当 tag==1时 第二个字段为 dlink
union
{
struct node * dlink;
char data;
} dd;
struct node * link ;
};
typedef struct node NODE;
int height(NODE* head){
if(!head->link)return 0;//空表深度为0
int ret=1;//
NODE* p=head->link;
while(p){//遍历链表的每一个结点,结点的最大深度加1即为链表的最大深度
if(p->tag==1){//当结点是广义表时
int h=height(p->dd.dlink)+1;//计算深度
ret=h>ret?h:ret;//更新最大深度
}
p=p->link;
}
return ret;
}
NODE* create(string s){//创建链表
NODE* head=new NODE;
NODE* p=head;
p->tag=0;
p->dd.data=-1;
NODE* temp;
for(int i=1;i<s.size()&&s[i]!=')';i++){
if(s[i]==',')continue;
if(isalpha(s[i])){
temp=new NODE;
temp->tag=0;
temp->dd.data=s[i];
}
else if(s[i]=='('){
temp=new NODE;
temp->tag=1;
temp->dd.dlink=create(s.substr(i));
while(i<s.size()&&s[i]!=')')i++;
}
p->link=temp;
p=p->link;
}
p->link=NULL;
return head;
}
int main(){
string s="()";
cout<<"Create link."<<endl;
NODE* head=create(s);
cout<<"Height:"<<height(head);
}
简单改动代码,测试在递归表的情况下height函数的递归深度
//对height函数作改动
int height(NODE* head,int depth){//depth记录height函数的递归深度
if(!head->link)return 0;//空表深度为0
int ret=1;//
NODE* p=head->link;
while(p){//遍历链表的每一个结点,结点的最大深度加1即为链表的最大深度
if(p->tag==1){//当结点是广义表时
int h=height(p->dd.dlink,depth+1)+1;//计算深度
ret=h>ret?h:ret;//更新最大深度
}
p=p->link;
}
return ret;
}
//对main函数作改动
int main(){
string s="(a,b)";
cout<<"Create link."<<endl;
NODE* head=create(s);
head->link->link->tag=1;
head->link->link->dd.dlink=head;//符合题目中给的例子:C=(a,C);
cout<<"Height:"<<height(head,0);
}
可以看到,递归深度达到26001,栈内存溢出,系统报错。实际上,递归表的深度是无穷大。
遍历广义表时,记录结点地址和经过次数,在遍历该结点的广义表时,如果某一结点经过了一次以上,则说明存在递归表。可用map实现。
bool is_recursive_link(NODE*head,map<NODE*,int>&nodecount){
NODE* p=head;
while(p){
nodecount[p]++;
if(nodecount[p]>1)return true;
if(p->tag==1){
return is_recursive_table(p->dd.dlink,nodecount);
}
p=p->link;
}
return false;
}
int main(){
string s="(a,b)";
cout<<"Create link."<<endl;
NODE* head=create(s);
head->link->link->tag=1;
head->link->link->dd.dlink=head;
map<NODE*,int>nodecount;
if(is_recursive_link(head,nodecount))
cout<<"This is a recursive link."<<endl;
// cout<<"Height:"<<height(head,0);
}
在写递归程序时,要特别注意:
-
警惕堆栈溢出
如果递归求解的数据规模很大,调用层次很深,一直压入栈,会有堆栈溢出的风险
-
设置中止条件
如果没有中止条件,递归函数就会无休止地被调用
-
减少重复运算
可以通过储存中间计算结果减少递归函数的调用