「数据结构」第四次作业

第四次作业

1. 栈操作(栈-基本题)

【问题描述】

假设给定的整数栈初始状态为空,栈的最大容量为100。从标准输入中输入一组栈操作,按操作顺序输出出栈元素序列。栈操作:1表示入栈操作,后跟一个整数(不为1、0和-1)为入栈元素;0表示出栈操作;-1表示操作结束。

【输入形式】

从标准输入读取一组栈操作,入栈的整数和表示栈操作的整数之间都以一个空格分隔。

【输出形式】

在一行上按照操作的顺序输出出栈元素序列,以一个空格分隔各元素,最后一个元素后也要有一个空格。如果栈状态为空时进行出栈操作,或栈满时进行入栈操作,则输出字符串“error”,并且字符串后也要有一空格。所有操作都执行完后,栈也有可能不为空。

【样例输入】

1 3 1 5 1 7 0 0 1 8 0 1 12 1 13 0 0 0 0 1 90 1 89 0 -1

【样例输出】

7 5 8 13 12 3 error 89

【样例说明】

入栈元素依次为3、5、7,然后有两次出栈动作,所以先输出7和5,这时栈中只有元素3;之后元素8入栈,又出栈,输出8;随后元素12和13入栈,再进行4次出栈操作,输出13、12和3,这时栈为空,再进行出栈操作会输出error;最后90和89入栈,进行一次出栈操作,输出89,栈中剩余1个元素。

【评分标准】

该题要求按照操作的顺序输出出栈元素序列,提交程序名为stack.c。

【参考答案】

手动模拟一个栈即可。

#include <stdio.h>
#include <stdlib.h>

int main()
{
	int order;
	int num;

	int stack[105];
	int stackp = 0;

	scanf("%d", &order);
	while (order != -1)
	{
		if (order == 1)
		{
			scanf("%d", &num);
			if (stackp == 100)
			{
				printf("error ");
			}
			else
			{
				stack[stackp++] = num;
			}
		}
		else
		{
			if (stackp == 0)
			{
				printf("error ");
			}
			else
			{
				printf("%d ", stack[--stackp]);
			}
		}
		scanf("%d", &order);
	}

	return 0;
}

2. C程序括号匹配检查

【问题描述】

编写一程序检查C源程序文件中{}、()等括号是否匹配,并输出第一个检测到的不匹配的括号及所对应括号所在的行号(程序中同一类括号只有一个不匹配)。

注意:

1.除了括号可能不匹配外,输入的C源程序无其它语法错误。

2.字符常量、字符串常量及注释中括号不应被处理,注释包括单行注释//和多行/* */注释

3.字符常量和字符串常量中不包含转义字符’和";

4.程序中出现有意义括号的个数不超过200个;

不匹配判断规则:

1.当检测的程序括号为’{‘时,若其前序尚未匹配的括号为’(‘时,输出该’('左括号及所在行号;

2.当遇到一个不匹配的右括号’)‘或’}'时,输出该右括号及所在行号;

3.当程序处理完毕时,还存在不匹配的左括号时,输出该左括号及所在行号。

【输入形式】

打开当前目录下文件example.c,查询其括号是否匹配。该文件中每行字符数不超过200。

【输出形式】

若存在括号不匹配时,应输出首先能判断出现不匹配的括号及其所在的行号。当出现括号不匹配时,按下面要求输出相关信息:

without maching at line

其中为‘{’, ‘}’, ‘(’, ‘)’等符号,为该符号所在的行号。

若整个程序括号匹配,则按下面所示顺序输出括号匹配情况,中间没有空格。

(){(()){}}

【样例输入1】

若当前目录下输入文件example.c中内容如下:

#include<stdio.h>

int main(){

printf(“{ hello world }\n”); // }

)

【样例输出1】

without maching ‘)’ at line 4

【样例输入2】

若当前目录下输入文件example.c中内容如下:

#include<stdio.h>

int main(){

printf(“{ hello world }d\n”); /* }*/

【样例输出2】

without maching ‘{’ at line 2

【样例输入3】

若当前目录下输入文件example.c中内容如下:

#include<stdio.h>

int main(){

printf(“{ hello world }d\n”); /* }*/

}

【样例输出3】

(){()}

【样例说明】

样例1:在注释部分和字符串中的括号不考虑,在将程序处理之后得到的括号序列是(){()),遇到右括号时与最近的左括号匹配,发现最后一个小括号和大括号不匹配。

样例2:处理之后的括号序列是(){(),在最后缺少了右大括号,那么应该输出与之相对应的左括号不匹配。

【参考答案】

手动模拟一个栈,把所有情况都判断到就行了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 1. 当检测的程序括号为'{'时,若其前序尚未匹配的括号为'('时,输出该'('左括号及所在行号; 
// 2. 当遇到一个不匹配的右括号')'或'}'时,输出该右括号及所在行号;
// 3. 当程序处理完毕时,还存在不匹配的左括号时,输出该左括号及所在行号。

struct
{
	int x;
	char type;
} stack[200];

int main()
{
	FILE *text = fopen("example.c", "r");

	char line[200];
	int stackp = -1;
	int line_cnt = 0;

	int note_flag = 0;
	int char_flag = 0;
	int string_flag = 0;
	
	char res[200];
	memset(res, 0, 200);
	int resp = 0;

	while (fgets(line, 200, text))
	{
		int len = strlen(line);
		for (int i = 0; i < len; i++)
		{
			if (note_flag)
			{
				if (line[i - 1] == '*' && line[i] == '/')
				{
					note_flag = 0;
				}
			}
			else if (char_flag)
			{
				if (line[i] == '\'')
				{
					char_flag = 0;
				}
			}
			else if (string_flag)
			{
				if (line[i] == '\"')
				{
					string_flag = 0;
				}
			}
			else
			{
				if (line[i] == '/')
				{
					if (i < len - 1 && line[i + 1] == '/')
					{
						break;
					}
					else if (i < len - 1 && line[i + 1] == '*')
					{
						note_flag = 1;
					}
				}
				else if (line[i] == '\'')
				{
					char_flag = 1;
				}
				else if (line[i] == '\"')
				{
					string_flag = 1;
				}
				else if (line[i] == '(')
				{
					stackp++;
					stack[stackp].x = line_cnt;
					stack[stackp].type = '(';
					res[resp++] = '(';
				}
				else if (line[i] == '{')
				{
					if (stackp != -1 && stack[stackp].type == '(')
					{
						printf("without maching '%c' at line %d", stack[stackp].type, stack[stackp].x + 1);
						return 0;
					}
					stackp++;
					stack[stackp].x = line_cnt;
					stack[stackp].type = '{';
					res[resp++] = '{';
				}
				else if (line[i] == ')')
				{
					if (stackp == -1 || stack[stackp].type != '(')
					{
						printf("without maching '%c' at line %d", line[i], line_cnt + 1);
						return 0;
					}
					stackp--;
					res[resp++] = ')';
				}
				else if (line[i] == '}')
				{
					if (stackp == -1 || stack[stackp].type != '{')
					{
						printf("without maching '%c' at line %d", line[i], line_cnt + 1);
						return 0;
					}
					stackp--;
					res[resp++] = '}';
				}
			}
		}
		line_cnt++;
	}

	if (stackp != -1)
	{
		printf("without maching '%c' at line %d", stack[0].type, stack[0].x + 1);
	}
	else
	{
		printf("%s", res);
	}

	return 0;
}

3. 计算器(表达式计算-后缀表达式实现,结果为浮点)

【问题描述】

从标准输入中读入一个算术运算表达式,如:24 / ( 1 + 5/3 + 36 / 6 / 2 - 2) * ( 12 / 2 / 2 )= ,计算表达式结果,并输出。

要求:

1、表达式运算符只有+、-、*、/,表达式末尾的=字符表示表达式输入结束,表达式中可能会出现空格;
2、表达式中会出现圆括号,括号可能嵌套,不会出现错误的表达式;

3、表达式中出现的操作数都是十进制整数常量;但要求运算结果为浮点型,例如:5/2结果应为2.5。

4、要求采用逆波兰表达式来实现表达式计算。

【输入形式】

从键盘输入一个以=结尾的算术运算表达式。操作符和操作数之间可以有空格分隔。

【输出形式】

在屏幕上输出计算结果,小数点后保留两位有效数字。

【样例输入】

24 / ( 1 + 5/3 + 36 / 6 / 2 - 2) * ( 12 / 2 / 2 ) =

【样例输出】

19.64

【样例说明】

按照运算符及括号优先级依次计算表达式的值。

【评分标准】

该题要求采用逆波兰表达式实现表达式运算,提交程序名为cal.c。

【参考答案】

我是采用一遍读入,然后处理数字、符号和空格的方式。因为输入是逆波兰式,所以用压栈的方式就能解决。

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 1000

double num[MAX + 5];
char cal[MAX + 5];
int pn = 0, pc = 0;
char c;

char scan()
{
	char tmp;
	do
	{
		tmp = getchar();
	} while (tmp == ' ');
	if (isdigit(tmp))
	{
		num[pn] = tmp - '0';
		tmp = getchar();
		while (isdigit(tmp))
		{
			num[pn] = num[pn] * 10 + tmp - '0';
			tmp = getchar();
		}
		pn++;
	}
	while (tmp == ' ')
		tmp = getchar();
	return tmp;
}

int compare(char a, char b)
{
	switch (a)
	{
	case '+':
	case '-':
		switch (b)
		{
		case '+':
		case '-':
		case '=':
		case ')':
			return 1;
		default:
			return -1;
		}
	case '*':
	case '/':
		switch (b)
		{
		case '(':
			return -1;
		default:
			return 1;
		}
	case '(':
		switch (b)
		{
		case ')':
			return 0;
		default:
			return -1;
		}
	case ')':
		return 1;
	case '=':
		return -1;
	}
	return 0;
}

double operate(double a, double b, char x)
{
	switch (x)
	{
	case '+':
		return a + b;
	case '-':
		return a - b;
	case '*':
		return a * b;
	case '/':
		return a / b;
	}
	return 0.0;
}

int main()
{
	cal[pc++] = '=';
	c = scan();
	//	printf("%d\n",num[0]);
	while (c != '=' || cal[pc - 1] != '=')
		switch (compare(cal[pc - 1], c))
		{
		case -1:
			cal[pc++] = c;
			c = scan();
			break;
		case 1:
			num[pn - 2] = operate(num[pn - 2], num[pn - 1], cal[pc - 1]);
			num[--pn] = 0;
			cal[--pc] = 0;
			break;
		case 0:
			cal[--pc] = 0;
			c = scan();
			break;
		}
	printf("%.2f", num[pn - 1]);
	return 0;
}

4. 文本编辑操作模拟(简)a

【问题描述】

编写一程序模拟文本编辑操作。首先从标准输入读取一行字符串(字符个数不超过512),该行字符串是已经过n(大于0,小于等于10)步编辑操作后的结果。然后从下一行读取n,以及已发生过的n步编辑操作,编辑操作分行输入,输入格式为:

op pos str

其中op为编辑操作命令编码(在此只有插入和删除操作,1表示插入或2表示删除操作);pos表示插入或删除的位置;str表示已经插入或删除的字符串(中间没有空格)。各数据间以一个空格分隔。

然后在空一行后,再分行输入当前将要进行的编辑操作,包括如下四种操作(操作编码分别为:1表示插入,2表示删除操作,3表示撤销(即undo操作),-1表示结束):

1 pos str

表示将在pos位置插入字符串str(中间没有空格),各数据间以一个空格分隔;

2 pos n

表示将从pos位置开始删除n个字符(各数据间以一个空格分隔),若要删除的字符个数多于已有字符个数(即在文本中从pos开始的字符个数小于n),则按实际字符数删除即可。(提示:为了能够撤销删除操作,应按“2 pos str”形式保存命令。)

3

表示撤销最近执行的插入或删除操作,可以进行多次撤销操作,注意:也可以撤销之前已经发生过的n步编辑操作中的操作。

-1

表示退出编辑操作,在屏幕上输出最终编辑后的文本。

要求:

1、上述所有输入的编辑操作中的字符串str都不包含空白字符(空格符、制表符或换行符);

2、插入操作中的位置pos大于等于0,并且小于等于当前文本的字符个数;0位置表示文本第一个字符的位置;若pos为当前文本的字符个数,则表示在文本最后插入字符串;

3、删除操作中的位置pos大于等于0,并且小于当前文字的字符个数;

4、若已无操作可撤销,则再进行撤销操作无效;

5、文本在编辑过程中,总字符个数不会超过512。

【输入形式】

先从键盘输入一行字符串,表示已经经过n步编辑操作后的文本串,然后在下一行输入一个正整数n,并分行输入n步插入或删除操作(表示按时间先后顺序已进行的操作),格式如上所述。随后空一行,再分行输入将要进行的编辑操作,格式如上所述。直到输入-1操作为止。

【输出形式】

在屏幕上输出最终编辑后的文本内容。

【样例输入】

A Stack is a container of objects that are inserted and removed according to the last-in first-out (LIFO) principle.???

4

1 20 ainer

2 0 ???

1 85 -

1 99 (LIFO)

3

2 110 10

1 110 Objects

2 98 1

2 0 1

2 108 10

3

3

3

-1

【样例输出】

A Stack is a container of objects that are inserted and removed according to the last-in first-out principle.Objects

【样例说明】

第一行输入的文本串是先后经过下面4次编辑操作后得到的:先在20位置插入了字符串ainer,然后删除了开始位置的字符串???,随后在85位置插入了一个字符-,最后在99位置插入了字符串(LIFO)。

随后输入了撤销操作,即撤销先前最后进行的“1 99 (LIFO)”操作,也就是将99位置的6个字符删除;

2 110 10:将文本串最后的字符串???删除;

1 110 Objects:在文本串末尾插入字符串Objects;

随后执行了三次删除操作,又执行了三次撤销操作,最后输入的-1表示编辑操作结束,在屏幕上输出最终编辑后的文本串。

【评分标准】

该程序要求编程模拟编辑操作,提交程序文件名为edit.c。

【参考答案】

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct stack
{
	int tag;
	int pos;
	char str[600];
} stack;

stack order[500];
char s[600];
int n, p = -1;

void insert(int pos, char *str1)
{
	int i;
	for (i = strlen(s); i >= pos; i--)
	{
		s[i + strlen(str1)] = s[i];
	}
	for (i = 0; i < strlen(str1); i++)
	{
		s[i + pos] = str1[i];
	}
}

void delete(int pos, int n1, char *str2)
{
	int i, a = strlen(s);
	for (i = 0; i < n1; i++)
	{
		str2[i] = s[i + pos];
	}
	for (i = pos; i + n1 < a; i++)
	{
		s[i] = s[i + n1];
	}
	s[i] = '\0';
	for (i++; i < a; i++)
	{
		s[i] = 0;
	}
}

int main()
{
	int i, j;
	int tag0, pos0, n0;
	char str0[600], tmp[600];
	fgets(s, 515, stdin);
	scanf("%d", &n);
	for (i = 0; i < n; i++)
	{
		scanf("\n%d%d%s", &tag0, &pos0, str0);
		p++;
		order[p].tag = tag0;
		order[p].pos = pos0;
		strcpy(order[p].str, str0);
	}
	scanf("\n%d", &tag0);
	while (tag0 != -1)
	{
		switch (tag0)
		{
		case 1:
			scanf("%d%s", &pos0, str0);
			insert(pos0, str0);
			p++;
			order[p].tag = tag0;
			order[p].pos = pos0;
			strcpy(order[p].str, str0);
			break;
		case 2:
			scanf("%d%d", &pos0, &n0);
			p++;
			delete (pos0, n0, order[p].str);
			order[p].tag = tag0;
			order[p].pos = pos0;
			break;
		case 3:
			if (order[p].tag == 1)
			{
				delete (order[p].pos, strlen(order[p].str), tmp);
				p--;
			}
			else
			{
				insert(order[p].pos, order[p].str);
				p--;
			}
			break;
		}
		scanf("\n%d", &tag0);
	}
	puts(s);
	return 0;
}

5. 银行排队模拟(生产者-消费者模拟) - 分类别

单独给这题开了另一篇文章。

6. 函数调用关系(选做,不计分)

【问题描述】

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

说明:

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

【评分标准】

该题要求对函数调用栈信息进行分析,提交程序名为stack.c。

【参考答案】

模拟一下调用关系就行。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct stack
{
	char data[25];
} s[205];
struct answer
{
	char name[25];
	int freq;
	char contain[12][25];
} ans[105];

int top = -1, pa = -1;

void search()
{
	int i;
	for (i = 0; i <= pa; i++)
		if (strcmp(s[top].data, ans[i].name) == 0)
			break;
	if (i > pa)
		strcpy(ans[++pa].name, s[top].data);
}

void count()
{
	int i, j;
	for (i = 0; i <= pa; i++)
		if (strcmp(s[top - 1].data, ans[i].name) == 0)
			break;
	for (j = 0; j < ans[i].freq; j++)
		if (strcmp(ans[i].contain[j], s[top].data) == 0)
			break;
	if (j == ans[i].freq)
	{
		strcpy(ans[i].contain[ans[i].freq], s[top].data);
		ans[i].freq++;
	}
}

int main()
{
	int oper, i, j;
	//    char func;
	scanf("%d%s", &oper, s[++top].data);
	strcpy(ans[++pa].name, s[top].data);
	while (top != -1)
	{
		scanf("%d", &oper);
		if (oper == 8)
		{
			scanf("%s", s[++top].data);
			search();
			count();
		}
		else
			top--;
	}
	for (i = 0; i <= pa; i++)
	{
		if (ans[i].freq)
		{
			printf("%s:", ans[i].name);
			for (j = 0; j < ans[i].freq; j++)
			{
				if (j < ans[i].freq - 1)
					printf("%s,", ans[i].contain[j]);
				else
					printf("%s", ans[i].contain[j]);
			}
			printf("\n");
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值