BUAA(2021春)函数调用关系(期末考试题)——和考前的预测题包装机一模一样,就问你们准不准

48 篇文章 154 订阅

看前须知

要点介绍和简要声明.

题目内容

问题描述

给定某能正常运行结束的用户函数调用栈信息(当一个函数被调用时将入栈,当调用返回时,将出栈)。编写程序,对函数调用栈信息进行分析,依据函数入栈和出栈信息,分析函数调用关系,即一个函数调用了哪些不同函数。并按运行时调用序输出调用关系
说明:

  1. 在一个函数中,同一函数有可能被调用多次,输出调用关系时只输出一次;若一个函数没有调用其它函数,则不输出调用关系;
  2. 函数运行时调用序是指函数在调用栈中的出现序
  3. 程序中不存在递归调用。函数名符合C语言标识符的规定,函数名长度不超过20,每个函数最多调用不超过10个不同函数,程序中用户定义的函数个数不超过100。

算法提示:当一个函数入栈时,它就是当前栈顶函数调用的一个函数。

输入形式

假设用5表示函数入栈操作;用0表示当前函数出栈。当操作为5(入栈)时,输入形式为:
<操作> <函数名>

当操作为0(出栈)时,输入形式为:

<操作>

所有入栈操作和出栈操作都是从标准输入分行输入,假设调用栈中函数个数最多不超过200。开始时,调用栈为空,当调用栈再次为空时,输入结束。

输出形式

运行时调用先后顺序输出函数调用关系到标准输出,每行为一个函数的调用关系信息,包括:函数名及被调用函数,函数与被调用函数间用一个英文冒号“:”分隔,被调用函数间用一个英文分号“;”分隔最后一个函数名后跟一个回车。若一个函数没有调用其它函数,则不输出。

样例

【样例输入】
5 main
5 input
0
5 mysqrt
0
5 findA
0
5 findB
5 area
5 mysin
0
5 mycos
0
5 mysqrt
0
0
0
5 findC
5 area
5 mysin
0
0
5 mysqrt
5 max
0
0
0
5 output
0
0
【样例输出】

main:input;mysqrt;findA;findB;findC;ouput
mysqrt:max
findB:area
area:mysin;mycos;mysqrt
findC:area;mysqrt

样例说明

按照运行时调用函数的先后顺序,依次输出了main、mysqrt、findB、area和findC的函数调用关系。其中main函数调用了6个函数,按照运行时调用序依次输出。注意:mysqrt函数先于findB等函数出现在栈中,虽然mysqrt调用max较晚,但要先输出其调用关系。

题解

思路详解

有一点点难度,但是我可以说这道题就是缝合题目(前提是把我的题解都看过以及写了我补充的题目)。

首先有一个难点,怎么存储这些函数名,怎么利用栈巧妙的存这些函数名。一般人都是二维数组存函数名来模拟栈,但是这很不靠谱,因为这里仅仅是在处理函数调用总栈,对于处理函数调用分栈,我们需要再加一维,我相信对于三维数组的应用大家都不太熟,所以这种做法不太可能实现。

那么我们就要思考怎么降一维,其实很简单,我们在北京地铁那道题中用了很类似的方法,直接搞一个名字数组,把每一个函数名赋予一个独特的编号这样就可以巧妙的降一维,就可以解决问题了。

第二个难点在于怎么处理任意栈的问题(不知道栈有多少个),这个问题的处理和包装机那道题一模一样,看了我的题解就很简单,加一维度就好,原本的top变成top[200],原本的stack【200】(当然这题我用的是s)变成stack[200][200]就行(正好的是上面的难点化简之后也是二维,多巧妙)。

参考代码

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>
#include<stdbool.h>
int stack[200];		//函数调用总栈 
int s[200][200];	
//函数调用分栈,横坐标的序号表示该函数,该行内存储的序号是该行号对应的函数内部调用的函数 
struct infor{
	char functionName[200]; //记录函数名,并赋予其一个特定编号 
}AllfunctionName[2000];
int flag=0,top=0,op,num=0,fID,topp[200];//topp是栈顶数组,对应的 s (函数调用分栈) 每一行 
char fName[200];
int FindName(char *s,int len)	//赋予函数名编号的函数 
{
	int i;
	for(i=0;i<len;i++)
			if(strcmp(s,AllfunctionName[i].functionName)==0)//如果有,返回编号 
				return i;
	strcpy(AllfunctionName[len].functionName,s);//如果没有,则加入,并返回新的编号 
	return len;
}
int main()
{	
	int i,j,k,t;
	while(flag==0 && (scanf("%d",&op)==1))	//如果函数调用总栈还有函数存在 
	{
		if(op==5)
		{
			scanf("%s",fName);	//录入 
			fID=FindName(fName,num);	//获得编号 
			stack[top]=fID;	//加入总栈 
			if(top>0)	//如果总栈里有函数 
			{
				s[stack[top-1]][topp[stack[top-1]]]=fID;	
				//利用算法提示:当一个函数入栈时,它就是当前栈顶函数调用的一个函数。 
				topp[stack[top-1]]++;	//分栈栈顶+1 
			}
			top++;//总栈栈顶+1 
		}
		else if(op==0)
		{
			top--;	//总栈栈顶-1 
		}
		num++;
		if(top==0)
			flag=1;	//总栈为空 
	}
	//去重
	for(i=0;i<200;i++)
	{
		if(topp[i]>0)	//如果某个函数存在调用关系 
		{
			for(j=0;j<topp[i];j++)
			{
				for(k=j+1;k<topp[i];k++)
				{
					if(s[i][j]==s[i][k])	//存在重复 
					{
						for(;k<topp[i];k++)
						{
							s[i][k]=s[i][k+1];	//覆盖去重 
						}
						topp[i]--;	//栈顶-1 
						k=j;	//回到原位准备再查(测试点3,4都是有3次以上的重复的调用) 
					}
				}
			}
		}
	} 
	for(i=0;i<200;i++)
	{
		if(topp[i]>0)	//如果某个函数存在调用关系 
		{
			printf("%s:",AllfunctionName[i].functionName);//输出 
			for(j=0;j<topp[i]-1;j++)
			{
				printf("%s;",AllfunctionName[s[i][j]].functionName);//输出 
			}
			printf("%s",AllfunctionName[s[i][j]].functionName);//输出 
			puts("");
		}
	}
	return 0;
}

补充测试的数据

能过样例的都可以过测试点1,2 ,5

测试点3,4(考察多个重复)

输入:
5 main

5 input

0
5 input

0
5 input

0
5 put

0
5 input

0
0

输出:
main:input;put

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值