BUAA数据结构与程序设计第一次作业复习

准备把之前的作业都再写一遍作为复习,方法可能并不是最佳的,如有大佬请指点啊~

扩展字符A(43min)

扩展字符A

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

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

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

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

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

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

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
void Expand(char*,int);
int main()
{
    char str[1000];
    gets(str);
    int newlen=strlen(str);

    int i=0;
    while(str[i]!='\0')
    {
        if(i>0&&i<newlen&&str[i]=='-')
        {
            if(str[i-1]>='a'&&str[i+1]<='z'||str[i-1]>='A'&&str[i+1]<='Z'||str[i-1]>='0'&&str[i+1]<='9')
            {
                int oldlen=strlen(str);
                Expand(str,i);
                newlen=strlen(str);
                i=i+(newlen-oldlen+1);
            }
        }
        i++;
    }
    printf(str);
}
void Expand(char* str,int i)
{
    int expandlen=str[i+1]-str[i-1]-1;
    int movelen=strlen(str)-i-1;
    memmove(str+i+1+expandlen-1,str+i+1,sizeof(char)*(movelen+1));
    int j=i;
    for(;j<i+expandlen;j++)
    {
        str[j]=str[j-1]+1;
    }
}

注:此题有以下需要注意的地方

  • 第一次做的时候还不知道有memmove这么好的函数,所以多写了好多行用于调整位置,但是这个函数在用的时候要注意,我们这里移动的是从 ‘ - ’ 到字符串末尾,包含‘\0’,而在代码中,movelen记录的长度仅为有效长度,因此在使用memmove的时候,最后一个参数应该给movelen+1;
  • 然后就是更新字符串以及下标这部分,我们画图看:
  • 在这里插入图片描述在扩展前,i为4,扩展后,怎么调整呢?
  • 扩展后字符串长度 – 扩展前字符串长度 + 1就是黄色部分的长度,我们设这个长度为x
  • i + x是不是就相当于i指向了g?然后在if语句之外,还有一个不受任何if约束的i++,那现在i是不是就指向g的下一位-了呀?至于g,不需要再参与到遍历当中。

表达式计算

这个题留到后面,我整理一个表达式计算的方法合集。

小数形式与科学计数法转换(简)(50min)

【问题描述】

编写一个程序,将用小数表示的浮点数,转换成科学计数法的形式输出。输入的数据没有符号,小数点前后必有数字,且全为有效数据,即小数点后的末尾数字不为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。

输入的小数有以下几种情况:
在这里插入图片描述

我们大体可以先分为这几种情况,然后再做具体操作

if(str[0]=='0')
{

}
else if(strlen(str)==1||str[0]>='0'&&str[0]<='9'&&str[1]=='.')
{

}
else if(strlen(str)>=3&&str[0]>='0'&&str[0]<='9'&&str[1]>='0'&&str[1]<='9')
{
    
}

第一种情况,小数点右移的数目等于从左向右数第一个非零的数的下标小数点下标。若小数点移到了最后一位,则最后一位赋值为‘\0’.

第二种情况,直接输出即可。

第三种情况,小数点左移次数等于小数点下标 – 1,如果是整数,则假设小数点在字符串末尾。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stdbool.h>
void transform_1(char*);
void transform_2(char*);
int main()
{
    char str[150];
    scanf("%s",str);
    
    if(str[0]=='0')
    {
        transform_1(str);
    }
    else if(strlen(str)==1||str[0]>='0'&&str[0]<='9'&&str[1]=='.')
    {
        printf("%se0",str);
    }
    else if(strlen(str)>=3&&str[0]>='0'&&str[0]<='9'&&str[1]>='0'&&str[1]<='9')
    {
        transform_2(str);
    }
    return 0;
}
void transform_1(char* str)
{
    int exponent=0;
    int i=0;
    for(;i<strlen(str);i++)
    {
        if(str[i]>'0'&&str[i]<'9')
        {
            exponent=1-i;
            break;
        }
    }
    if(str[i+1]!='\0')
    {
        memmove(str+i+1+1,str+i+1,sizeof(char)*(strlen(str)-i));
        str[i+1]='.';
        memmove(str,str+i,sizeof(char)*(strlen(str)-i+1));
        printf("%se%d",str,exponent);
    }
    else
    {
        printf("%ce%d",str[i],exponent);
    }
}
void transform_2(char*str)
{
    int exponent=0;
    char*p=strchr(str,'.');
    if(p==NULL)
    {
        int len=strlen(str);
        str[len]='.';
        str[len+1]='\0';
        exponent=len-1;
        memmove(str+2,str+1,sizeof(char)*(strlen(str)));
        str[1]='.';
    }
    else
    {
        exponent=p-str-1;
        int i=p-str;
        memmove(str+i,str+i+1,sizeof(char)*(strlen(str)-i));
        memmove(str+2,str+1,sizeof(char)*strlen(str));
        str[1]='.';
    }
    int j=strlen(str)-1;
    while(str[j]!='.')
    {
        if(str[j]=='0')
        {
            str[j]='\0';
            j--;
        }
        else
        {
            break;
        }
    }
    if(str[strlen(str)]=='.')
        str[strlen(str)]='\0';
    printf("%se%d",str,exponent);
}

超长正整数的减法(71min)

【问题描述】
编写程序实现两个超长正整数(每个最长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<string.h>
#include<stdlib.h>
int flag=0;
void front_zero(char*);
void subtract(char*,char*);
void reverse(char*);

int main()
{
    char minuend[100];
    char subtran[100];
    gets(minuend);
    gets(subtran);
    front_zero(minuend);
    front_zero(subtran);

    if(strlen(minuend)<strlen(subtran))
    {
        flag=1;
        char tmp[100];
        strcpy(tmp,minuend);
        strcpy(minuend,subtran);
        strcpy(subtran,tmp);
    }
    else if(strlen(minuend)==strlen(subtran))
    { 
        int cmp=strcmp(minuend,subtran);
        if(cmp==0)
        {
            printf("0");
            exit(1);
        }
        else if(cmp<0)
        {
            flag=1;
            char tmp[100];
            strcpy(tmp,minuend);
            strcpy(minuend,subtran);
            strcpy(subtran,tmp);
        }
    }   
    
    subtract(minuend,subtran);

}
void reverse(char* a)
{
    int i,j;
    for(i=0,j=strlen(a)-1;i<j;i++,j--)
    {
        char tmp=a[i];
        a[i]=a[j];
        a[j]=tmp;
    }
}
void subtract(char*a,char*b)
{
    char c[100];
    reverse(a);
    reverse(b);
    
    int j=0;
    int x,y;
    while(b[j]!='\0')
    {
        if(a[j]<b[j])
        {
            x=a[j]-'0'+10;
            y=b[j]-'0';
            a[j+1]--;   
        }
        else
        {
            x=a[j]-'0';
            y=b[j]-'0';
        }
        c[j]=x-y+'0';
        j++;
    }
    c[j]='\0';
    if(b[j]=='\0'&&a[j]!='\0')
    {
        strcat(c,a+j);
    }
    reverse(c);
    front_zero(c);
    if(flag==1)
    {
        printf("-%s",c);
    }
    else
        printf("%s",c);
}
void front_zero(char* str)
{   
   
    if(strlen(str)>1&&str[0]=='0')
    {
        int j=0;
        while(str[j++]=='0');
        j--;
        memmove(str,str+j,sizeof(char)*(strlen(str)-j+1));
    }
}
  • 这道题要注意的是:
  • 要先判断大小,大的做被减数,小的做减数,如果调换,那么最后输出的时候打印负号
  • 做减法时要先逆转字符串
  • 最后要给差也前端去零
  • 调换字符串的时候,不要用指针很容易错,就老老实实地用strcpy三次

全排列数的生成

【问题描述】输入整数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增大时,运行时间将急剧增加。在编程时要注意尽量优化算法,提高运行效率。
【评分标准】该题要求输出若干行整数。。

这道题我当时是看一个b站视频写的,up讲的真的超级好,链接放这里有需要的自取哈,记得给up三连link
主要思想就是递归,想不明白的可以画一画递归展开图,一会儿给大家放个事例:

#include<stdio.h>
#include<stdlib.h>
void perm(int [],int,int);
void printArry(int [],int);
void swap(int [],int,int);
void swapback(int [],int,int);
int main()
{
    int N;
    scanf("%d",&N);
    
    int* arr=(int*)malloc(sizeof(int)*N);
    for(int i=0;i<N;i++)
    {
        arr[i]=i+1;
    }
    perm(arr,0,N-1);
    return 0;
}
void perm(int arr[],int p,int q)
{
    if(p==q)
    {
        printArry(arr,q+1);
        return;
    }
    else
    {
        for(int i=p;i<=q;i++)
        {
            swap(arr,p,i);
            perm(arr,p+1,q);
            swapback(arr,p,i);
        }
    }
}
void printArry(int arr[],int n)
{
    for(int i=0;i<n;i++)
    {
        printf("%d ",arr[i]);
    }
    printf("\n");
}
void swap(int arr[],int p,int q)
{
    int temp=arr[q];
    for(int i=q;i>=p+1;i--)
    {
        arr[i]=arr[i-1];
    }
    arr[p]=temp;
}
void swapback(int arr[],int p,int q)
{
    int temp=arr[p];
    for(int i=p;i<=q-1;i++)
    {
        arr[i]=arr[i+1];
    }
    arr[q]=temp;
}

在这里插入图片描述

  • 简化思路就是,把每一位数与第一位数进行字典序的交换,然后让后面的数进行排列直至只剩一个数。

好啦今天就复习完毕了,明天接着肝剩下的内容(呜呜呜内容好多大佬保佑我)

  • 49
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值