函数调用关系——数据结构栈类型题

大家好呀!栈是数据结构当中最为简单易懂又实用的数据结构,凭借着“后入后出"的特点实现许多功能。今天的题目用来模拟函数调用关系,还是有一定难度的,正好能够巩固对堆栈的认识。

目录

问题描述

输入形式

输出形式

样例输入

样例输出

样例说明

解题思路

代码实现


问题描述

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

说明:

1. 在一个函数中,同一函数有可能被调用多次,输出调用关系时只输出一次;若一个函数没有调用其它函数,则不输出调用关系;

2. 函数运行时调用序是指函数在调用栈中的出现序。

3. 程序中不存在递归调用。函数名符合C语言标识符的规定,函数名长度不超过20,每个函数最多调用不超过10个不同函数,程序中用户定义的函数个数不超过100。

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

输入形式

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

<操作> <函数名>  

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

<操作>

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

输出形式

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

样例输入

8 main

8 input

0

8 mysqrt

0

8 findA

0

8 findB

8 area

8 mysin

0

8 mycos

0

8 mysqrt

0

0

0

8 findC

8 area

8 mysin

0

0

8 mysqrt

8 max

0

0

0

8 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较晚,但要先输出其调用关系。

解题思路

这道题相当考验对栈的掌握能力! 通过设置大大小小不同功能的栈,实现解题。

该题最大的难点在于:每连续调用三个函数(即连续入栈),那么第二个函数需要再次开设一个栈来存储这个函数的调用关系。比如f(x),g(x),h(x)连续入栈,那么第一个栈存储f(x),g(x),然后以g(x)为栈底再开设一个栈,存储g(x),h(x)。h(x)出栈后,g(x)栈不再使用,再进来函数的话仍然将它堆入f(x)的栈。该如何实现这个想法?
我们不妨考虑一个三维数组stack[N][N][N],第一维用于建造新的栈,第二维用于每个栈函数的堆积,第三维用于存储函数名。用图像来演示是这样的:

 因为最后以函数出现的顺序输出,所以还要有专门的数组来按出现顺序储存函数名称。这里为stackstring[N][N]。

设b[N]为当前读入的函数名,c[N]为上一次读入的函数名。

num[N]用于统计当前栈内实际上有多少层函数的堆积。

因为函数调用需要从一个栈跳到另一个栈,所以需要有一个栈来记录跳跃的路径。这里为stackint[N],topint记录栈顶。

算法思想如下:

  1. 若为函数入栈,则先与已经存在的栈的栈底函数进行比较。如果出现相同的函数,则说明该函数之前已经创建过栈了,只需要再重复使用这个栈就好了;如果没有,就为这个函数新建一个栈。k用来判断。
  2. 如果上一步操作是出栈,那这个函数只需要在当前栈进入就好。先与这个栈内所有的函数进行比较。如果出现相同的函数,则说明该函数之前已经进入这个栈了,就不用再进入一次了。如果没有,就把他堆入当前的栈里。v用来判断。
  3. 如果上一步操作不是出栈,那么就来到我们在最初讨论的情况:多个函数连续调用,需要建立新栈。先将c与已经存在的栈的栈底函数进行比较。如果出现相同的函数,则说明该函数之前已经创建过栈了,只需要再重复使用这个栈就好了;如果没有,就为这个函数新建一个栈。t用来判断。再将b与这个栈内所有的函数进行比较。如果出现相同的函数,则说明该函数之前已经进入这个栈了,就不用再进入一次了。如果没有,就把他堆入当前的栈里。u用来判断。这一步是本思路的重点。
  4. 若为函数出栈,将b清空,从该栈栈顶退出一个函数。如果栈内仅剩栈底一个函数了,那么这个栈不再使用,回到stackint所记录的上一个栈内,并调整回来后这个栈的函数数量。
  5. 入栈与出栈函数数量相等后退出循环。按照出现顺序输出函数关系。

代码实现

#include <stdio.h>
#include <string.h>
char stack[205][205][205],stackstring[205][205];
int toprow=0,topcolumn[205]={0},max=0,stackint[205]={0},topint=1,topstring=-1;
int main()
{
	int a,num[205]={0},h,i,j,t=0,u=0,v=0,k=0;
	char b[205]={},c[205]={};
	while (scanf("%d",&a))
	{
		if (a==8)
		{
			strcpy(c,b);
			scanf("%s",b);
			for (i=0;i<=topstring;i++)
			{
				if (strcmp(stackstring[i],b)==0)
				{
					k=1;
					break;
				}
			}
			if (k==0)
			{
				strcpy(stackstring[++topstring],b);
			}
			k=0;
			if (c[0]=='\0')
			{
				for (i=1;i<topcolumn[toprow];i++)
				{
					if (strcmp(b,stack[toprow][i])==0)
					{
						v=1;
						break;
					}
				}
				if (v==0) strcpy(stack[toprow][topcolumn[toprow]++],b);
				v=0;
				num[toprow]++;
			}
			else 
			{
				for (i=0;i<=max;i++)
				{
					if (strcmp(c,stack[i][0])==0)
					{
						toprow=i;
						if (toprow!=0) stackint[topint++]=i;
						t=1;
						for (j=1;j<topcolumn[toprow];j++)
						{
							if (strcmp(b,stack[toprow][j])==0)
							{
								u=1;
								break;
							}
						}
						if (u==0)
						{
							strcpy(stack[toprow][topcolumn[toprow]++],b);
						}
						u=0;
						if (toprow!=0) num[toprow]+=2;
						else num[toprow]+=1;
						break;
					}
				}
				if (t==0)
				{
					max++;
					toprow=max;
					stackint[topint++]=max;
					strcpy(stack[toprow][0],c);
					strcpy(stack[toprow][1],b);
					topcolumn[toprow]=2;
					num[toprow]=2;
				}
				t=0;
			}
		}
		if (a==0)
		{
			num[toprow]--;
			b[0]='\0';
			if (num[toprow]==0)
			{
				topint--;
				if (topint==0) break;
				toprow=stackint[topint-1];
				num[toprow]--;
			}
		}
	}
	for (h=0;h<=topstring;h++){
	for (i=0;i<=max;i++)
	{
		if (strcmp(stackstring[h],stack[i][0])==0)
		{
		printf("%s:",stack[i][0]);
		for (j=1;j<topcolumn[i]-1;j++)
		{
			printf("%s,",stack[i][j]);
		}
		printf("%s\n",stack[i][topcolumn[i]-1]);
		break;
		}
	}}
	return 0;
}


这道题需要的逻辑能力好强,作者表示差点看不懂自己之前写的代码(((φ(◎ロ◎;)φ)))

恐怕当时的水平高于现在/(ㄒoㄒ)/~~大家觉得这道题怎么样呢~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值