「数据结构」第一次作业

本文提供了五个编程挑战,包括扩展带有连接符的字符、计算整数算术表达式、将小数转化为科学计数法、执行超长正整数的减法以及生成全排列数。每个挑战都给出了详细的问题描述、输入输出示例和部分参考代码,旨在考察编程者对字符串处理、表达式解析和算法实现的能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文发布于Hibiki33’s Blog,转载请标明出处。
代码仅供参考,查重结果自负。

1. 扩展字符A

【问题描述】
从键盘输入包含扩展符 '-' 的字符串,将其扩展为等价的完整字符,例如将 a-d 扩展为 abcd ,并输出扩展后的字符串。

要求:只处理[a-z][A-Z][0-9]范围内的字符扩展,即只有当扩展符前后的字符同时是小写字母、大写字母或数字,并且扩展符后的字符大于扩展符前的字符时才进行扩展,其它情况不进行扩展,原样输出。例如:a-RD-e0-b4-B等字符串都不进行扩展。

【输入形式】
从键盘输入包含扩展符的字符串
【输出形式】
输出扩展后的字符串

【输入样例1】
ADEa-g-m02
【输出样例1】
ADEabcdefghijklm02

【输入样例2】
cdeT-bcd
【输出样例2】
cdeT-bcd

【样例说明】
将样例1的输入ADEa-g-m02扩展为:ADEabcdefghijklm02;样例2的输入cdeT-bcd中,扩展符前的字符为大写字母,扩展符后的字符为小写字母,不在同一范围内,所以不进行扩展。
【评分标准】
该题要求扩展字符,提交程序文件 expand.c

【参考答案】
按照题目要求分析和输出即可,注意判断 [a-z][A-Z][0-9] 可用 <ctype.h> 中现成的函数,没必要自己造轮子。

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

int is_fit(char c1, char c2)
{
    if (((islower(c1) && islower(c2))
        || (isupper(c1) && isupper(c2))
        || (isdigit(c1) && isdigit(c2))) && (c1 < c2))
    {
        return 1;
    }
    return 0;
}

int main()
{
    char str_in[100];
    gets(str_in);

    char *start = str_in;
    char *end;

    while ((end = strchr(start, '-')) != NULL)
    {
        while(start != end)
        {
            printf("%c", *start++);
        }
        if (is_fit(*(end - 1), *(end + 1)))
        {
            for (char i = *(end - 1) + 1; i != *(end + 1); i++)
            {
                printf("%c", i);
            }
        }
        else 
        {
            printf("%c", *end++);
        }
        start++;
    }
    while (*start != 0)
    {
        printf("%c", *start++);
    }

    return 0;
}

2. 表达式计算(支持空格,连乘,连除)

【问题描述】

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

要求:
1、表达式运算符只有+、-、*、/,表达式末尾的’=’字符表示表达式输入结束,表达式中可能会出现空格;
2、表达式中不含圆括号,不会出现错误的表达式;
3、出现除号/时,以整数相除进行运算,结果仍为整数,例如:5/3结果应为1。

【输入形式】

在控制台中输入一个以’=’结尾的整数算术运算表达式。

【输出形式】

向控制台输出计算结果(为整数)。

【样例1输入】

5 - 1 * 2 * 3 + 12 / 2 / 2 =

【样例1输出】

2

【样例2输入】

500 =

【样例2输出】

500

【样例1说明】

输入的表达式为5 - 1 * 2 * 3 + 12 / 2 / 2 =,按照整数运算规则,计算结果为2,故输出2。

【样例2说明】

输入的表达式为500 = ,没有运算符参与运算,故直接输出500。

算法之一提示:
1、可以利用gets函数,读取整行表达式;
2、对于空格,可以考虑首先去除表达式中的所有空格
3、可以设一计数器用来记录已读取、但未参加运算的运算符的个数,根据该计数器来判断如何进行运算;
4、可以设计一函数:实现二元整数算术运算。

【评分标准】

该题要求输出整数表达式的计算结果,共有5个测试点。上传C语言文件名为example1c.c

【参考答案】
表达式计算是一种非常经典的题目,通过数据结构的学习你会掌握至少3种计算算术表达式的方法,之后还会出现括号等各种情况。单纯对这题来讲,因为不涉及括号,所以如果用最基本的方法,那么先算乘除后算加减即可。

简单的表达式计算:

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

int calc(int a, char op, int b)
{
	switch (op)
	{
		case '+':
			return a + b;
		case '-':
			return a - b;
		case '*':
			return a * b;
		case '/':
			return a / b;
		default : break;
	}
	return 0;
}

int main()
{
	char expr_in[200];
	gets(expr_in);

	int expr[200] = {0};
	int sign_cnt = 0;
	for (int i = 0, j = 0; expr_in[i] != '='; i++)
	{
		if (expr_in[i] == ' ')
		{
			continue;
		}
		if (isdigit(expr_in[i]) && !(j % 2))	// 偶数位存数字 奇数位存符号
		{
			expr[j] = expr[j] * 10 + expr_in[i] - '0';
		}
		else if (isdigit(expr_in[i]) && j % 2)
		{
			expr[++j] = expr_in[i] - '0';
		}
		else
		{
			expr[++j] = expr_in[i];
			sign_cnt++;
		}
	}

	for (int i = 0, flag = 1; i < sign_cnt; i++)
	{
		int pos = 2 * i + 1;
		switch (expr[pos])
		{
			case '*':
			case '/':
				expr[pos + 1] = calc(expr[pos - 1], (char)expr[pos], expr[pos + 1]);
				expr[pos - 1] = 0;
				expr[pos] = 44 - flag;		// 通过flag标记正负
				break;
			case '+':
				flag = 1;
				break;
			case '-':
				flag = -1;
				break;
			default: break;
		}
	}

	for (int i = 0; i < sign_cnt; i++)
	{
		int pos = 2 * i + 1;
		expr[pos + 1] = calc(expr[pos - 1], (char)expr[pos], expr[pos + 1]);
	}

	printf("%d", expr[2 * sign_cnt]);

	return 0;
}

用压栈的方法计算:

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

int num[1005];
char sign[1005];
int pn = 0;
int ps = 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;
	}
}

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

int main()
{
	sign[ps++] = '=';
	c = scan();
	while (c != '=' || sign[ps - 1] != '=')
	{	
		switch (compare(sign[ps - 1], c))
		{
		case -1:
			sign[ps++] = c;
			c = scan();
			break;
		case 1:
			num[pn - 2] = operate(num[pn - 2], num[pn - 1], sign[ps - 1]);
			num[--pn] = 0;
			sign[--ps] = 0;
			break;
		case 0:
			sign[--ps] = 0;
			c = scan();
			break;
		}
	}
	printf("%d", num[pn - 1]);
	return 0;
}

3. 小数形式与科学计数法转换(简)

【问题描述】

编写一个程序,将用小数表示的浮点数,转换成科学计数法的形式输出。输入的数据没有符号,小数点前后必有数字,且全为有效数据,即小数点后的末尾数字不为0;小数点前若只有一位数字,可以为0,否则小数点前的最高位数字不为0。

提示:以字符串形式保存相关数据。

【输入形式】

从控制台输入一小数,最后有回车换行符,所有输入的字符数不会超过100。

【输出形式】

以科学计数法形式输出数据。输出的数据由以下几部分构成:
1.底数部分是一个小数或整数,若为小数,则小数点前后必有数字,而且都为有效数字。即:小数点前只有一位大于0的数字,小数点后的末尾数字不能为0。若为整数,则只有一位数字,不带小数点。
2.必有小写字母“e”。
3.指数部分是一个整数,若大于等于0,则不带正号“+”。若小于0,则需要带负号“-”,且整数的最高位数字不为0。

【输入样例1】

0.000000000000002

【输出样例1】

2e-15

【输入样例2】

8.9845623489651700659

【输出样例2】

8.9845623489651700659e0

【输入样例3】

367298599999093453490394859509568659795603.4

【输出样例3】

3.672985999990934534903948595095686597956034e41

【样例说明】

以小数形式输入数据,然后转换成科学计数法形式输出。

【评分标准】

该题要求以科学计数法形式输出数据,提交程序文件名为notation.c

【参考答案】
没啥难度,看清题目就行。

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

char s[10000];
char zhengshu[10000];
char xiaoshu[10000];

int main()
{
	int cnt1 = 0;
	int cnt2 = 0;
	int i = 0;
	int j;
	int tmp;

	gets(s);

	while (s[i] != '.')
	{
		zhengshu[cnt1++] = s[i++];
	}
	for (cnt2 = 0, i += 1; s[i] != '\0'; cnt2++)
	{
		xiaoshu[cnt2] = s[i++];
	}
	if (cnt1 > 1)
	{
		printf("%c.", zhengshu[0]);
		for (j = 1; j < cnt1; j++)
		{
			printf("%c", zhengshu[j]);
		}
		for (j = 0; j < cnt2; j++)
		{
			printf("%c", xiaoshu[j]);
		}
		printf("e%d", cnt1 - 1);
	}
	else if (cnt1 == 1 && zhengshu[0] != '0')
	{
		printf("%c.", zhengshu[0]);
		for (j = 0; j < cnt2; j++)
		{
			printf("%c", xiaoshu[j]);
		}
		printf("e0");
	}
	else
	{
		for (j = 0; j < cnt2; j++)
		{
			if (xiaoshu[j] != '0')
			{
				break;
			}
		}
		printf("%c", xiaoshu[j]);
		tmp = j + 1;
		if (j + 1 < cnt2)
		{
			printf(".");
			for (j++; j < cnt2; j++)
			{
				printf("%c", xiaoshu[j]);
			}
			printf("e-%d", tmp);
		}
		else
		{
			printf("e-%d", tmp);
		}
	}
	
	return 0;
}

4. 超长正整数的减法

【问题描述】
编写程序实现两个超长正整数(每个最长80位数字)的减法运算。

【输入形式】

从键盘读入两个整数,要考虑输入高位可能为0的情况(如00083)。

  1. 第一行是超长正整数A;

  2. 第二行是超长正整数B;

【输出形式】
输出只有一行,是长整数A减去长整数B的运算结果,从高到低依次输出各位数字。要求:若结果为0,则只输出一个0;否则输出的结果的最高位不能为0,并且各位数字紧密输出。
【输入样例】
234098
134098703578230056

【输出样例】
-134098703577995958

【样例说明】
进行两个正整数减法运算, 234098 -134098703578230056 = -134098703577995958

【评分标准】
完全正确得20分,每个测试点4分,提交程序文件名为subtract.c

【参考答案】
就是高精减,类比于列竖式。对于字符串的处理会比较麻烦。

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

void high_sub(char *up, char *down)
{
	char res[200];
	char *p = res;

	for (int i = strlen(up) - 1; i >= 0; i--)
	{
		if (up[i] >= down[i])
		{
			res[i] = up[i] - down[i] + '0';
		}
		else
		{
			res[i] = 10 + up[i] - down[i] + '0';
			int j = i - 1;
			while (up[j] == 0)
			{
				up[j] = 9;
			}
			up[j]--;
		}
	}
	
	while (*p == '0')
	{
		p++;
	}

	puts(p);
}

int main()
{
	char a0[200];
	char b0[200];

	memset(a0, '0', 50);
	memset(b0, '0', 50);
	char *a1 = a0 + 50;
	char *b1 = b0 + 50;

	while ((*a1 = getchar()) == '0') {}
	gets(a1 + 1);
	while ((*b1 = getchar()) == '0') {}
	gets(b1 + 1);

	int l1 = strlen(a1);
	int l2 = strlen(b1);

	char *a;
	char *b;
	if (l1 > l2) 
	{
		a = a1;
		b = b1 - l1 + l2;
	}
	else
	{
		b = b1;
		a = a1 - l2 + l1;
	}

	if (strcmp(a, b) > 0)
	{
		high_sub(a, b);
	}
	else if (strcmp(a, b) < 0)
	{
		printf("-");
		high_sub(b, a);
	}
	else
	{
		printf("0");
	}

	return 0;
}

5. 全排列数的生成

【问题描述】输入整数N( 1 <= N <= 10 ),生成从1~N所有整数的全排列。
【输入形式】输入整数N。
【输出形式】输出有N!行,每行都是从1~N所有整数的一个全排列,各整数之间以空格分隔。各行上的全排列不重复。输出各行遵循“小数优先”原则, 在各全排列中,较小的数尽量靠前输出。如果将每行上的输出看成一个数字,则所有输出构成升序数列。具体格式见输出样例。
【样例输入1】1
【样例输出1】1
【样例说明1】输入整数N=1,其全排列只有一种。
【样例输入2】3
【样例输出2】
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
【样例说明2】输入整数N=3,要求整数1、2、3的所有全排列, 共有N!=6行。且先输出1开头的所有排列数,再输出2开头的所有排列数,最后输出3开头的所有排列数。在以1开头的所有全排列中同样遵循此原则。
【样例输入3】10
【样例输出3】
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 10 9
1 2 3 4 5 6 7 9 8 10
1 2 3 4 5 6 7 9 10 8
1 2 3 4 5 6 7 10 8 9
1 2 3 4 5 6 7 10 9 8
1 2 3 4 5 6 8 7 9 10
1 2 3 4 5 6 8 7 10 9
1 2 3 4 5 6 8 9 7 10
1 2 3 4 5 6 8 9 10 7
……………………
【样例说明3】输入整数N=10,要求整数1、2、3、……、10的所有全排列。上例显示了输出的前10行。
【运行时限】要求每次运行时间限制在20秒之内。超出该时间则认为程序错误。提示:当N增大时,运行时间将急剧增加。在编程时要注意尽量优化算法,提高运行效率。
【评分标准】该题要求输出若干行整数。

【参考答案】
这题的难点在于怎样按照字典序输出,并且要保证时间复杂度。如果有一定知识储备不难发现这题是一道典型的DFS,如果不知道可以学习这个回溯算法入门级详解 + 练习 - 全排列

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

int finished[10];
int answer[10];
int n;

void dfs(int cnt)
{
	if (cnt == n)
	{
		for (int i = 0; i < n; i++)
		{
			printf("%d ", answer[i]);
		}
		printf("\n");
		return;
	}
	else
	{
		for (int i = 1; i <= n; i++)
		{
			if (!finished[i])
			{
				answer[cnt] = i;
				finished[i] = 1;
				dfs(cnt + 1);
				finished[i] = 0;
			}
		}
	}
}

int main()
{
	scanf("%d", &n);

	dfs(0);

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值