11_02二进制表示


前言

之前将近一个星期都在忙CATIA去了,CSDN被搁在一边,当时写好的都忘了发。今天回到对学校逆天题目的分享上


题目

在这里插入图片描述

有问题的思路历程

注:以下内容处于我个人的想法,一定程度上受对编程里二进制运算知识应用欠缺的影响。可以跳过
写一个函数能输出n的二进制对应位数
代码如下

#include<stdio.h>
#include<math.h>
int sec1(int n){
    int i = 0;
    while(pow(2,i)<=n)
        i++;
    i--;
    return i;
}

void sec(int arr[],int n){
    int i = 0;
    while(pow(2,i)<=n)
        i++;
    //printf("%d\n",i);
    i--;
    int t=0;
    while(n>0){
        if(n-pow(2,i)>0){
            arr[t]=i;
            t++;
            n-=pow(2,i);
        }
        i--;
    }
}
int main() {
    int arr[100];
    int n=0,j=0;
    scanf("%d",&n);
    int m = n;
    sec(arr,m);
    while(j<=sec1(n)&&arr[j]>=0){
    printf("%d  ",arr[j]);
    j++;
    }
	return 0;
    }

结果:在这里插入图片描述
虽然看起来距离正确答案有点接近了,但是这样写存在很大的潜在问题:首先是对于奇数,2
的零次方是不会在输出中有体现的;其次,二进制表示的过程存在多次迭代,会使main函数里的调用杂乱不堪。
推荐采用递归函数来解决问题


答案

老师的解法

#include<stdio.h>
#include<math.h>
void putqupoly(int t)
{   int i = 8*sizeof(int), b ,flag = 0;  
    for(b=1<<(i-1);i>=0;  )
    {   t<<=1;
        i--;                             
        if(t&b)                       
        {
            if (flag)
                printf("+");
            if (i>=3)
            {
                printf("2(");
                putqupoly(i-1);
                printf(")");
            }
            else if (i==2)
                printf("2");
            else if (i==1)
                printf("2(0)");
            flag=1;
        }
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    putqupoly(n);
    return 0;
}

老师的解法与我一开始想的不同,是将输入数从二进制高位开始一个一个往下算,即123=2^6+ 25+24+23+21+2^0,则将6一步算到底,输出2(2(2)+2)之后再对下一位5进行转换。

同时,由于题目中对n的范围有所界定,为1到10000之间的数,则n其实已经被涵盖在所有int型数据之中,而int型在储存时最多能储存32/64位二进制数(根据计算机配置而定,因此采用8*sizeof(int)的保守写法)

b=1<<(i-1)将b左移至最高位,即此时b的二进制表示为100000……共30个0。
注:
(1)因为int型第一位为符号位,故正数b与t的第一位一定是相等的,因此在迭代时直接从第二位开始;
(2)此处1<<(i-1)表示将1的二进制位左移,而不是将二进制的1左移,因此相当于把二进制第零位上的1左移(i-1)位;

接着进入for循环:

t<<=1;将t左移一位。(为啥放在for循环开头其实我也不太理解,个人推测可能是因为不论是32bit还是64bit,首位的二进制表示值都远远大于10000,所以放在前面影响不大。望大佬指正)

这一步就像一个断头台,而后面if(t&b) 则是一把铡刀,将t的二进制高位一个一个截取。
在这里插入图片描述

记得在进入if语句前执行i--;,一是因为需要用i来判断t的左移次数,进而判断是否可以出循环;二是因为

if (flag) printf("+");只是为了满足题目输出要求而设,每经历一次循环,flag便会被赋1,以便下一次循环时先打“+”号。

当i>=3时,进入第二个if语句,其中
printf("2("); printf(")");是用来打印结果中的首尾部分;
putqupoly(i-1);是对其对应位数的再次二进制化,为什么要用i-1呢,我们可以举个例子看看:
例如:当t=7时,t的二进制为00……00000111(共32-3=29个0),在i–至i=3后,进入if语句,执行 putqupoly(3-1);,最终输出2(2)
看出以上内容错在哪里了吗,
留意注:(1)
因为b是0100……00(32-2=30个0),而从for循环中可以看出,t每左移一位,i才–。因此,t左移至第2位时,需左移29-1=28次,而i也因此–了28次,i=32-28=4.所以在i=4时便可以进入if语句 putqupoly(4-1);最终输出2(2+2(0)) 。

以上就是所有关于老师提供的解法的分享。可以说是main函数最没面子的一集。
不过老师的解法给了我一点灵感,既然题目变态,那我也玩

抽象

int main() {
    int arr[100];
    int n=0,j=0;
    scanf("%d",&n);
    int m = n;
    sec(arr,m);
    while(j<=sec1(n)&&arr[j]>=0){
            switch (arr[j]){
                case 14:printf("2(2(3)+2(2)+2)+");break;
                case 13:printf("2(2(3)+2(2)+2(0))+");break;
                case 12:printf("2(2(3)+2(2))+");break;
                case 11:printf("2(2(3)+2+2(0))+");break;
                case 10:printf("2(2(3)+2)+");break;
                case 9:printf("2(2(3)+2(0))+");break;
                case 8:printf("2(2(3))+");break;
                case 7:printf("2(2(2)+2+2(0))+");break;
                case 6:printf("2(2(2)+2)+");break;
                case 5:printf("2(2(2)+2(0))+");break;
                case 4:printf("2(2(2))+");break;
                case 3:printf("2+2(2(0))+");break;
                case 2:printf("2+");break;
                case 1:printf("2(0)+");break;
            }
    //printf("%d  ",arr[j]);
    j++;
    }
    printf("\b ");
	return 0;
}

在这里插入图片描述

不做解释!!!遥遥领先

总结

最近比较忙,可能做不到日更,抱歉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值