NJUPT 程序设计周

作者: Du1in9 | 来源:发表于2021-11-04 15:23 被阅读0次

A3_众数问题

图1 功能框架图 图2 数组存储算法图 图3 频率统计算法图 图4 求数组重数算法图 图5 调整重数算法图 图6 核心设计流程图
  • 众数问题_B19030825.cpp
#include <iostream>
#include <cstring>
#include <stdlib.h>
using namespace std;

int main(){ 
    int n,i,j,temp;                                 //临时输入存入 temp 
    int array[1000][2]={(0,0)};                     //可存放1000个自然数及其频率 
re: cout<<"\n>> 请输入自然数个数n:";    cin>>n;             //自然数个数
    if(n<=0){                                       //错误输入 n 
        cout<<"\nERROR:请输入正数!\n";
        goto re;    
    }
    cout<<"\n>> 请输入n个自然数:";
    for(i=0;i<n;i++){ 
re2:    cin>>array[i][0];
        if(array[i][0]<0){                          //错误输入自然数 
            cout<<"\nERROR:请输入自然数!\n";
            goto re2;
        }
    }
    for(i=0;i<n;i++){                               //统计自然数出现次数 
        for(j=0;j<n;j++){
            if(array[j][0]==array[i][0])
                array[i][1]++;
        }
    }
    int max=0;
    for(i=0;i<n;i++){                               //统计数组重数 
        if(array[i][1]>max)
            max=array[i][1];
        cout<<"\n自然数:"<<array[i][0]<<" 频率:"<<array[i][1]*1.0/n<<endl;
    } 
    for(i=0;i<n;i++){                               //将重复众数的重数置 0,避免重复输出 
        if(array[i][1]==max){
            for(j=i+1;j<n;j++){                     //只保留第一次出现的众数 
                if(array[j][0]==array[i][0])
                    array[i][1]=0;
            }           
        }
    }
    for(i=0;i<n;i++){                               //输出所有众数、重数 
        if(array[i][1]==max)
            cout<<"\n集合S的众数:"<<array[i][0]<<" 重数:"<<array[i][1]<<endl; 
    } 
    return 0; 
}
图7 测试结果截图一 图8 测试结果截图二 图9 测试结果截图三 图10 测试结果截图四

程序调试过程中的问题

问题1:最开始想的是用链表结点存储数组元素,但是遍历结点的值总是和预期效果不一致,而且调试的时候总是报错。
解决方法:采用自己更熟练的二维数组数据结构存储。
问题2:输出重数以及众数的时候,重复输出。
解决方法:意识到一个重要的规律:重数只能有一个,而众数可以有多个。所以可以将多个相同众数的重数调整为一个,此时不在需要用到重复的众数,将其置0,最后得到数组所有不重复众数的重数。
问题3:刚开始准备沿用临时链表结点的思想,创建另一个二维数组存储众数,却发现代码冗长。
解决方法:直接用同一个二维数组存储、计算、输出。
问题4:在调试的时候,输出频率竟然随机出错。
解决方法:局部变量n是终端输入,而计算频率时array[i][1]用到了n,当时array的初始化为array[][2]={(0,0)},没有明确指明n。所以改为array[1000][2]={(0,0)}解决了问题。

B3_大整数算术运算器

图1 功能框架图 图2 字符串转换/倒序存储算法图 图3 比较大整数大小算法图 图4 大整数加法算法图 图5 大整数减法算法图 图6 大整数乘法算法图 图7 大整数除法算法图 图8 核心设计流程图
  • 大整数算术运算器_B19030825.cpp
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;

struct big_number{                      //大整数结构体
    int d[1000];
    int len;                            //大整数位数 
    big_number(){                       //构造函数,用来初始化 
        d[1000]={0}; 
        len=0;
    }
}; 
    
big_number change(char str[]){          //将大整数字符串存储在结构体 
    big_number x;   
    x.len=strlen(str);
    for(int i=0;i<x.len;i++)            //把大整数的低位切换为高位
        x.d[i]=str[x.len-i-1]-'0';      //例:str='12345', a=[5,4,3,2,1] 
    return x; 
} 

int compare(big_number a,big_number b){ //比较两个大整数的大小
    if(a.len>b.len)return 1;            //a大于b,返回 1 
    else if(a.len<b.len)return 0;       //a小于b,返回 0 
    else{
        for(int i=a.len-1;i>=0;i++){    //从高位到低位逐一比较 
            if(a.d[i]>b.d[i])return 1;
            else if(a.d[i]<b.d[i])return 0;
        }
    } 
    return 1; 
}

big_number add(big_number a,big_number b){//1、加法运算 
    big_number c;
    int carry=0,temp;                   //进位标志,本位和 
    int i;
    for(i=0;i<b.len;i++){               //从低位到高位相加 
        temp=a.d[i]+b.d[i]+carry;
        c.d[c.len++]=temp%10;    
//      cout<<"\ncarry:"<<carry<<" temp:"<<temp<<" result:"<<c.d[i]<<endl;  
        carry=temp/10; 
    }
    if(carry!=0)                        //如果最高位进位
       c.d[c.len++]=a.d[i++]+carry; 
    for(;i<a.len;i++)                        
        c.d[c.len++]=a.d[i];         
    return c;
} 

big_number sub(big_number a,big_number b){//2、减法运算 
    big_number c;
    int i;
    for(i=0;i<b.len;i++){
//      int carry=0;
        if(a.d[i]<b.d[i]) {             //如果不够减,向高位借 
            if(a.d[i+1]>0){             //如果高位为正 
                a.d[i+1]--;         
                a.d[i]+=10; 
            }
            else{                       //如果高位为 0 
                a.d[i+1]=9;         
                a.d[i]+=10;             
            } 
//      carry=-1;
        }
        c.d[c.len++]=a.d[i]-b.d[i];
//      cout<<"\ncarry:"<<carry<<" a[i]:"<<a.d[i]<<" b[i]:"<<b.d[i]<<" result:"<<c.d[c.len-1]<<endl; 
    }
    //方案A:先 c.len=a.len,再遍历 i<a.len求得 c。例:a=10345,b=123,c=00000->10222
    //方案B:先遍历 i<b.len,再将 a的高位赋值给 c。例:a=10345,b=123,c=222->10222
    for(;i<a.len;i++)                   //这里采用的方案 B      
        c.d[c.len++]=a.d[i];
    while(c.len-1>=1&&c.d[c.len-1]==0)
        c.len--;                        //去除为 0的高位,同时保留一个最低位 
    return c;
} 

big_number multi(big_number a,int b){   //3、乘法运算 
    big_number c;
    int carry=0;
    for(int i=0;i<a.len;i++){           //a从低位到高位依次乘 b 
        int temp=a.d[i]*b+carry;
        c.d[c.len++]=temp%10;
//      cout<<"a[i]:"<<a.d[i]<<" b:"<<b<<" carry:"<<carry<<" temp:"<<temp<<" c[i]:"<<c.d[c.len-1]<<endl;
        carry=temp/10;
    }
    while(carry!=0){                    //如果最高位进位
        c.d[c.len++]=carry%10;
        carry/=10;
    }
    return c;
} 

big_number divide(big_number a,int b,int &r){//4、除法运算 
    big_number c;
    c.len=a.len;
    for(int i=a.len-1;i>=0;i--){            //a从高位到低位依次除 b 
        r=r*10+a.d[i];
        if(r<b) c.d[i]=0;
        else{
            c.d[i]=r/b;
            r=r%b;
        }
//      cout<<"a[i]:"<<a.d[i]<<" r:"<<r<<" b:"<<b<<" c[i]:"<<c.d[i]<<endl; 
    } 
    while(c.len-1>=1&&c.d[c.len-1]==0)
        c.len--;                            //去除为0的高位,同时保留一个最低位
    return c;
} 

void print(big_number a){                   //终端输出 
    for(int i=a.len-1;i>=0;i--)
        printf("%d",a.d[i]);
}

void show(char line1[1000],char line2[1000],char ysf){//输出文本内容 
    cout<<"\na: "<<line1<<endl; 
    cout<<"\nb: "<<line2<<endl; 
    cout<<"\n运算符: "<<ysf<<endl; 
}

void put_wb(big_number result,FILE *wb2){   //保存结果到文本 
    for(int i=result.len;i>=0;i--)
        fprintf(wb2,"%d",result.d[i]);
}

void ZDCZ(){
    char str1[1000],str2[1000];             //可以存储1000位大整数
    big_number a,b;                         //加数,减数,被乘数,被除数 
    int r,c,d;                              //乘数,除数,余数  
    cout<<"\n【 1:大整数加法 2:大整数减法 3:大整数乘法 4:大整数除法 5:退出 】\n";
re: cout<<"\n>> 请输入操作选项:";      char choice2;   cin>>choice2; 
    switch(choice2){
        case '1':
            cout<<"\n>> 请输入大整数a、b:";    cin>>str1>>str2;
            a=change(str1);                 b=change(str2);
            cout<<"\na+b= ";                
            if(compare(a,b))                print(add(a,b));
            else                            print(add(b,a));
            cout<<endl;                     goto re;
        case '2':
            cout<<"\n>> 请输入大整数a、b:";    cin>>str1>>str2;
            a=change(str1);                 b=change(str2);              
            cout<<"\na-b= ";                
            if(compare(a,b))                print(sub(a,b));
            else{
                cout<<"-";  
                print(sub(b,a));
            }
            cout<<endl;                     goto re;
        case '3':                           //能力有限,要求被乘数不超过 8位 
            cout<<"\n>> 请输入大整数a、b:";    cin>>str1>>c;
            a=change(str1);
            cout<<"\na*b= ";                print(multi(a,c));
            cout<<endl;                     goto re;
        case '4':                           //能力有限,要求被除数不超过 8位 
re2:        cout<<"\n>> 请输入大整数a、b:";    cin>>str1>>d;
            if(d==0){
                cout<<"\nERROR:除数不能为0,请重新输入!\n";
                goto re2;
            }
            a=change(str1);                 r=0;    
            cout<<"\na/b= ";                print(divide(a,d,r));
            cout<<"···"<<r<<endl;       goto re;
        case '5':
            break; 
        default:
            cout<<"\nERROR:输入错误,请重新输入!\n"; goto re; 
    }
}

void WBCZ(){ 
    big_number a,b;                         //加数,减数,乘数,除数 
    int r=0,c,d,result;                     //被乘数,被除数,余数,运算结果 
    char line1[1000],line2[1000],line3[1000];
    FILE *wb = fopen("ab.txt","r");
    FILE *wb2 = fopen("result.txt","w");
    if(!wb) cout<<"\nwarning:文本为空!\n"; 
    fscanf(wb,"%s",line1);  
    fscanf(wb,"%s",line2);  
    fscanf(wb,"%s",line3);  
    switch(line3[0]){
        case '+':
            show(line1,line2,line3[0]);
            a=change(line1);    b=change(line2);
            fprintf(wb2,"a+b= ");
            put_wb(add(a,b),wb2); 
            cout<<"\nSuccessfully:运算结果已经写入文本!\n"; 
            break;
        case '-':
            show(line1,line2,line3[0]); 
            a=change(line1);    b=change(line2);
            if(compare(a,b)){
                fprintf(wb2,"a-b= ");
                put_wb(sub(a,b),wb2);
            }
            else{
                fprintf(wb2,"a-b= -");
                put_wb(sub(b,a),wb2);
            }
            cout<<"\nSuccessfully:运算结果已经写入文本!\n";  
            break;
        case '*':
            show(line1,line2,line3[0]); 
            a=change(line1);    c=atoi(line2);
            fprintf(wb2,"a*b= ");
            put_wb(multi(a,c),wb2);
            cout<<"\nSuccessfully:运算结果已经写入文本!\n";    
            break;
        case '/':
            show(line1,line2,line3[0]); 
            a=change(line1);    d=atoi(line2);
            if(d==0){
                cout<<"\nERROR:除数不能为0,请重新输入!\n";
                goto close;
            }
            fprintf(wb2,"a/b= ");
            put_wb(divide(a,d,r),wb2);
            fprintf(wb2," ··· %d",r);   
            cout<<"\nSuccessfully:运算结果已经写入文本!\n"; 
            break;
        default:
            cout<<"\nERROR:运算符错误,或文本为空!\n";      
            break;
    }
close:fclose(wb);
}

int main(){
    cout<<"\n【 方案A:终端输入、输出 】\n\n【 方案B:文本输入、输出 】\n";
    cout<<"\n>> 请输入操作选项:";  char choice;    cin>>choice;
    if(choice=='A') {ZDCZ();    return 0;}      //终端操作 
    if(choice=='B') {WBCZ();    return 0;}      //文本操作 
}
图9 测试结果截图一 图10 测试结果截图二 图11 测试结果截图三 图12 测试结果截图四 图13 测试结果截图五 图14 测试结果截图六 图15 测试结果截图七 图16 测试结果截图八 图17 测试结果截图九 图18 测试结果截图十 图19 测试结果截图十一

程序调试过程中的问题

问题1:在编写乘法和除法时,我意识到不再是一位一位的处理数据,而是将乘数(除数)看作一个整体,而被乘数(被除数)仍然当作结构体(大整数数组)处理。
解决方法:将乘法和除法的乘数(除数)改为int类型即可。
问题2:在编写文本操作之乘法和除法时,第二行不能用change函数转换。
解决方法:因为change函数是将字符串转数组,所以换做将字符串转整型即可(利用algothorm库的atoi函数)。
问题3:在编写调整减法高位位置时,发现不能采用像加法那样遍历较大数的位数。
解决方法:方案A:先 c.len=a.len,再遍历 i<a.len求得 c。例:a=10345,b=123,c=00000->10222。方案B:先遍历 i<b.len,再将 a的高位赋值给 c。例:a=10345,b=123,c=222->10222
问题4:在调试减法时,发现当a<b时输出错误。
解决方法:因为采用的数组存储的大整数,所以当a<b时,减出来高位可能会为负。创建一个compare函数,先比较两数大小,保证sub函数参数传入时:第一个数大于等于第二个数。然后输出时前面加上负号即可。

课程设计总结

通过这次实验设计,我懂得了当程序编写遇到问题时不要顽固自封,不要守着一个方法做,换一种思路从头再来可能更加顺利。在刚开始编写时,虽然做到了实验要求里基本的简单输入要求,但当输入数据值、数据量情况多变时,就会出现错误。而这样的结果并不完美,这样的程序没有普适性,更没有实用性。所以我们应该不断优化自己的代码,不断考虑各种终端的操作情况,因为写出来的程序不光是拿给自己用,也是给别人用。如果用户的输入不在你的意料之中而出现报错,那么这个程序就失败了。这次B3实验我写的代码虽然成功运行了,但是还有一些bug需要优化,比如:终端/文本操作不能一次输入多个表达式(终端只能多次输入一个表达式),加法运算不支持负数输入(而是偷懒转线用减法),而乘法和除法没有做到两个(>20位)大整数的计算。

A3_众数问题拓展:界面实现

#include <graphics.h>                                                   // 引用图形库头文件
#include <stdio.h>
#include <windows.h>                                                    
#include <string.h>
#include <iostream>
#include <cstring>

using namespace std;

int r[3][4] = { {30,20,100,80},{140,20,210,80},{250,20,320,80} };       //三个按钮的二维数组
char s[30];                                                             //输入字符串变量

int button_judge(int x, int y){                                         //按钮判断函数
    if (x > r[0][0] && x<r[0][2] && y>r[0][1] && y < r[0][3])return 1;
    if (x > r[1][0] && x<r[1][2] && y>r[1][1] && y < r[1][3])return 2;
    if (x > r[2][0] && x<r[2][2] && y>r[2][1] && y < r[2][3])return 3;
    return 0;
}

void simulation(int n,int array[1000][2]){                              //运行函数
    int i,j;
    for(i=0;i<n;i++){                               //统计自然数出现次数 
        for(j=0;j<n;j++){
            if(array[j][0]==array[i][0])
                array[i][1]++;
        }
    }
    int max=0;
    for(i=0;i<n;i++){                               //统计数组重数 
        if(array[i][1]>max)
            max=array[i][1];
        cout<<"当前自然数:"<<array[i][0]<<" 频率:"<<array[i][1]*1.0/n<<endl;
    } 
    for(i=0;i<n;i++){                               //将重复众数的重数置 0,避免重复输出 
        if(array[i][1]==max){
            for(j=i+1;j<n;j++){                     //只保留第一次出现的众数 
                if(array[j][0]==array[i][0])
                    array[i][1]=0;
            }           
        }
    }
    for(i=0;i<n;i++){                               //输出所有众数、重数 
        if(array[i][1]==max)
            cout<<"集合S的众数:"<<array[i][0]<<" 重数:"<<array[i][1]<<endl; 
    } 
}

int main(){
    int array[1000][2] = { (0,0) };
    int event = 0,n,i;                                                  //n是自然数个数
    short win_width, win_height;                                        //定义窗口的宽度和高度
    win_width = 350;win_height = 100;
    initgraph(win_width, win_height);                                   //初始化窗口
    for (i = 0;i < 256;i += 5){                                         //窗口颜色动态变化,由黑变白
        setbkcolor(RGB(i, i, i));                                       
        cleardevice();                                                  //清屏
        Sleep(30);                                                      //延时30ms
    }
    RECT R1 = { r[0][0],r[0][1],r[0][2],r[0][3] };
    RECT R2 = { r[1][0],r[1][1],r[1][2],r[1][3] };
    RECT R3 = { r[2][0],r[2][1],r[2][2],r[2][3] };
    LOGFONT f;                                                          //字体样式指针
    gettextstyle(&f);                                                   //获取字体样式
    _tcscpy(f.lfFaceName, _T("宋体"));                                    //修改字体样式为宋体
    f.lfQuality = ANTIALIASED_QUALITY;                                  //修改字体样式为平滑 
    settextstyle(&f);                                                   //设置字体样式
    settextcolor(BLACK);                                                //设置字体黑色
    drawtext("输入", &R1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);        //在矩形区域R1内输入文字,水平居中,垂直居中,单行显示
    drawtext("运行", &R2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);        //在矩形区域R2内输入文字,水平居中,垂直居中,单行显示
    drawtext("打印", &R3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);        //在矩形区域R3内输入文字,水平居中,垂直居中,单行显示
    setlinecolor(BLACK);                                                //保存边框黑色
    rectangle(r[0][0], r[0][1], r[0][2], r[0][3]);
    rectangle(r[1][0], r[1][1], r[1][2], r[1][3]);
    rectangle(r[2][0], r[2][1], r[2][2], r[2][3]);
    MOUSEMSG m;                                                         //鼠标指针

    while (true){
        m = GetMouseMsg();                                              //获取一条鼠标消息
        switch (m.uMsg){
        case WM_MOUSEMOVE:
            setrop2(R2_XORPEN);
            setlinecolor(LIGHTCYAN);                                    //线条颜色为亮青
            setlinestyle(PS_SOLID, 3);                                  //设置画线为实线,10磅
            setfillcolor(WHITE);                                        //填充颜色为白色
            if (button_judge(m.x, m.y) != 0){
                if (event != button_judge(m.x, m.y)){
                    event = button_judge(m.x, m.y);                     //记录这一次触发的按钮
                    fillrectangle(r[event - 1][0], r[event - 1][1], r[event - 1][2], r[event - 1][3]);//有框填充矩形(X1,Y1,X2,Y2)
                }
            }
            else{
                if (event != 0){                                        //上次触发的按钮未被修正为原来的颜色
                    fillrectangle(r[event - 1][0], r[event - 1][1], r[event - 1][2], r[event - 1][3]);//两次同或为原来颜色
                    event = 0;
                }
            }
            break;
        case WM_LBUTTONDOWN:
            switch (button_judge(m.x, m.y)){                            //按照按钮判断左键单击后的操作
            case 1:
                InputBox(s, 30, "请输入n");                                //1、输入参数
                sscanf(s, "%d", &n);
                for (int i = 0;i < n;i++) {
                    InputBox(s, 30, "请输入n个自然数");
                    sscanf(s, "%d", &array[i][0]);
                }
                FlushMouseMsgBuffer();                                  //单击事件后清空鼠标消息
                break;
            case 2:
                simulation(n,array);                                    //2、运行函数
                FlushMouseMsgBuffer();                                  //单击事件后清空鼠标消息
                break;
            case 3:
                closegraph();                                           //3、关闭绘图环境
                exit(0);
            default:
                FlushMouseMsgBuffer();                                  //单击事件后清空鼠标消息
                printf("\n打印鼠标坐标:(%d,%d)\n",m.x,m.y);           //方便调试时确定区域
                break;
            }
            break;
        }
    }
    return 0;
}

B3_大整数运算拓展:python实现

import math

a = input("a: ")
b = input("b: ")
x = input("x: ")
y = input("y: ")

result = str(int(a) + int(b))
print("a+b= " + result)
result = str(int(a) - int(b))
print("a-b= " + result)
result = str(int(a) * int(b))
print("a*b= " + result)
result = str(int(a) // int(b))
r = str(int(a) % int(b))
print("a/b= " + result + "···" + r)
result = str(math.isqrt(int(x)))
r = str(int(x) - (math.isqrt(int(x))) ^ 2)
print("sqrt(x)= " + result + "···" + r)
result = str(math.pow(int(x), int(y)))
print("pow(x,y)= " + result)

相关文章

  • NJUPT 程序设计周

    A3_众数问题 众数问题_B19030825.cpp 程序调试过程中的问题 问题1:最开始想的是用链表结点存储数组...

  • NJUPT 程序设计周

    备案一 Keylogger.py demo.py test1.py test2.py test3.py 演示视频:...

  • NJUPT《JAVA程序设计》

    1/3 课堂练习 第一次作业第二次作业第三次作业第四次作业第五次作业第六次作业 设计图第六次作业_代码图第七次作业...

  • Writeup1.EasyOverrideVariable1

    Question1: NJUPT-CGCTF-Whendidyouborn? Analysis1.0: Glanc...

  • NJUPT【 面向对象程序设计及C++ 】

    Part 1/6 考试范围 第1章面向对象的三大特征,类和对象,程序开发过程第2章cin、cout,::,全局变量...

  • 验证码识别程序设计流程

    以南邮正方教务系统为例 找到验证码图片的链接 "http://jwxt.njupt.edu.cnCheckCode...

  • 字符串比较

    图片来源moocC语言程序设计进阶-第一周测试

  • NJUPT《 大学英语 Ⅲ 》

    一、考试说明 ① 听力:短新闻、长对话、短文听力,35分;② 词汇选择,共20题,10分;(前四个单元词汇)③ 阅...

  • NJUPT【 数学实验 】

    考试说明 ① 在线考试(50%)② 实验报告(50%) Part1 实验报告 Part2 命令总结 求两个正整数的...

  • NJUPT《 大学英语 》

    《 大学英语 Ⅰ 》 Unit 1 Growing Up Text A:Writing for Myself of...

网友评论

    本文标题:NJUPT 程序设计周

    本文链接:https://www.haomeiwen.com/subject/agnqzltx.html