数学问题——进制转换

例题1——进制转换(十进制---->二进制)

题目描述:将超大的十进制正整数,转化为对应的二进制形式。

解题思路:这题主要的难点,是十进制数的范围很大。

解题阶段一

        用字符串形式来存储数字,不断进行对2取模和对2整除运算,以期求出结果。

        但是提交代码进行在线测试的时候,出现超时的报错。

        我当时以为这种算法本身就比较费时,就没有再深究代码bug,换了其他的思路。然而后面发现,代码的strDiv函数存在各种漏洞,详细请见解题阶段三

#include <iostream>
using namespace std;
string strDiv(string str,int& mod){   // 这里n是1~9的整数
    int remainder=0;
    string res="";
    char temp;
    for(int i=0;i<str.size();i++){
        remainder*=10;
        remainder += (str[i]-'0');
        temp = remainder/2 + '0';
        res+=temp;
        remainder%=2;
    }
    mod = remainder;
    return res;
}
int main(){
    string n;
    while(cin>>n){
        string ans="";
        char temp;
        int mod;
        if(n=="0"){
            cout<<"0"<<endl;
            continue;
        }
        while(n!="0"){
            n=strDiv(n,mod);
            temp = mod+'0';
            ans = temp + ans;
        }
        cout<<ans<<endl;
    }
    return 0;
}

解题阶段二

  1. 从需要转换的十进制数找到与之最接近的2的幂次方,并从这个十进制数中减去 该2的幂次方,在剩下的余数中重复这种做法,直到余数为0。
  2. 然后将所得到的这些2的幂次方与二进制数中的位权相比,相同的位标记为1,其余的位0,这样就可得到目标结果。

        需要注意的是,有关string形式的运算操作,需要自己手写函数。我以为这种方法还挺快的,但是在线测试的时候发现,虽然代码通过了测试,但是效率与预期相比还是稍微有点低。应该是自己手写的函数,还不够简洁。

#include <iostream>
#include <queue>
using namespace std;
const int MAXN=101;
int strCmp(string str1,string str2){   // 两个数字字符串大小的比较,str1<str2: -1, str1==str2: 0, str1>str2: 1
    int len1 = str1.size();
    int len2 = str2.size();
    if(len1<len2) return -1;
    else if(len1>len2) return 1;
    else{
        if(str1<str2) return -1;
        else if(str1>str2) return 1;
        else return 0;
    }
}
string strSub(string str,string sub){   // 返回str - sub 的结果,这里保证str的数值大于sub的数值
    int carry = 0,j=str.size()-1;
    for(int i=sub.size()-1;i>=0&&j>=0;i--,j--){
        int elem1,elem2;
        elem1=str[j]-'0'+carry;
        elem2=sub[i]-'0';
        carry=0;
        if(elem1<elem2){
            carry=-1;
            elem1+=10;
        }
        str[j]=(elem1-elem2) + '0';
    }
    while(carry==-1&&j>=0){
        int elem = str[j]-'0';
        elem+=carry;
        if(elem>=0) {
            str[j] = elem + '0';
            carry=0;
        }else{
            elem+=10;
            str[j] = elem + '0';
            j--;
        }
    }
    int pos=0;   // 寻找首个非0下标
    while(str[pos]=='0'){
        pos++;
    }
    if(pos==str.size()) return "0";
    return str.substr(pos);
}
string strMul(string str,int n){   // n暂时限制为1~9之间的整数
    int carry=0;
    string res="";
    char temp;
    for(int i=str.size()-1;i>=0;i--){
        carry+=(str[i]-'0')*n;
        temp = carry%10+'0';
        res = temp+res;
        carry/=10;
    }
    while(carry>0){
        temp = carry%10+'0';
        res = temp+res;
        carry/=10;
    }
    int pos=0;   // 寻找首个非0下标
    while(str[pos]=='0'){
        pos++;
    }
    if(pos==str.size()) return "0";
    return str.substr(pos);
}
string arr[MAXN];
void Initial(){
    arr[0]="1";
    for(int i=1;i<MAXN;i++){
        arr[i] = strMul(arr[i-1],2);
    }
}
int main(){
    Initial();
    string input;
    while(cin>>input){
        queue<int> myQueue;
        for(int i=MAXN-1;i>=0;i--){
            if(strCmp(input,arr[i])!=-1){
                myQueue.push(i);
                input = strSub(input,arr[i]);
            }
        }
        if(myQueue.empty()){
            cout<<"0"<<endl;
            continue;
        }
        int maxPos = myQueue.front();
        myQueue.pop();
        string ans="1";
        for(int i=maxPos-1;i>=0;i--){
            if(myQueue.empty()==true || myQueue.front()!=i) ans+="0";
            else{
                myQueue.pop();
                ans+="1";
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

解题阶段三

        看了王道机试指南的题解,才发现解题阶段一的思路其实可行的,把strDiv函数中的bug完善好(bug是:未考虑到str为"00000"这种情况,需要在函数末尾处进行对应的处理),就能通过测试,代码比较简洁,而且在测试中耗时也小了一些。

这给我的一个教训是:

        自己手写的函数,一定要单独多测试几遍,把一些容易出错的边界数据拿来测试,不要一昧求快,草草应付测试。

#include <iostream>
using namespace std;
string strDiv(string str) {  // 这里n是1-9的整数,是
    int remainder=0;
    string res="";
    char temp;
    for(int i=0; i<str.size(); i++) {
        remainder*=10;
        remainder += (str[i]-'0');
        temp = remainder/2 + '0';
        res+=temp;
        remainder%=2;
    }
    int pos=0;   // 寻找首个非0下标
    while(pos<res.size()&&res[pos]=='0')
        pos++;
    if(pos==res.size())
        return "0";
    return res.substr(pos);
}
int main() {
    string n;
    while(cin>>n) {
        if(n=="0") {
            cout<<"0"<<endl;
            continue;
        }
        string ans="";
        while(n!="0") {
            char temp;
            temp = (n[n.size()-1]-'0')%2 + '0';
            n=strDiv(n);
            ans = temp + ans;
        }
        cout<<ans<<endl;
    }
    return 0;
}

例题2——10进制 VS 2进制(十进制<---->二进制)

#include <iostream>
using namespace std;
string strMul(string str, int n){     // 乘法 n是1~9的整数
    int carry=0,len=str.size();
    string res="";
    for(int i=len-1;i>=0;i--){
        carry = carry+(str[i]-'0')*n;
        char temp = carry%10 + '0';
        res = temp + res;
        carry/=10;
    }
    while(carry>0){
        char temp = carry%10 + '0';
        res = temp + res;
        carry/=10;
    }
    int pos=0;
    while(pos<res.size()&&res[pos]=='0')
        pos++;
    if(pos==res.size()) return "0";
    return res;
}
string strAdd(string str1,string str2){  // 加法 假定str1的长度 >= str2的长度
    if(str1.size()<str2.size())
        swap(str1,str2);
    int carry=0,len1=str1.size(),len2=str2.size(),j,i;
    string res="";
    for(i=len1-1,j=len2-1;i>=0&&j>=0;i--,j--){
        carry = carry + (str1[i]-'0') + (str2[j]-'0');
        char temp = carry%10 + '0';
        res = temp + res;
        carry/=10;
    }
    while(carry!=0){
        if(i>=0){
            carry = carry + (str1[i]-'0');
            i--;
        }
        char temp = carry%10 + '0';
        res = temp + res;
        carry/=10;
    }
    if(i>=0){
        res = str1.substr(0,i+1) + res;
    }
    int pos = 0;
    while(pos<res.size()&&res[pos]=='0')
        pos++;
    if(pos==res.size()) return "0";
    return res.substr(pos);
}
string strDiv(string str,int n){     // 除法 n是1~9的整数
    int remainder=0,len=str.size();
    string res="";
    for(int i=0;i<len;i++){
        remainder*=10;
        remainder+=(str[i]-'0');
        char temp = remainder/n + '0';
        res = res + temp;
        remainder%=n;
    }
    int pos=0;
    while(pos<res.size()&&res[pos]=='0')
        pos++;
    if(pos==res.size()) return "0";
    return res.substr(pos);
}
int main() {
    /*string str="1";
    for(int i=1;i<=6000;i++){
        str = strMul(str,2);
        if(str.size()>1000){    // 此时i=3322
            cout<<i<<endl;
            break;
        }
    }*/
    string input;
    while(cin>>input){
        if(input=="0"){
            cout<<"0"<<endl;
            continue;
        }
        string erjinzhi="";
        while(input!="0"){
            char temp = ((input[input.size()-1]-'0')%2) +'0';
            erjinzhi = temp + erjinzhi;
            input = strDiv(input,2);
        }
        int len=erjinzhi.size();
        int pos = len-1;
        while(pos>=0&&erjinzhi[pos]=='0')
            pos--;
        string ans="0",elem="1";
        for(int i=0;i<=pos;i++){
            if(erjinzhi[i]=='1')
                ans = strAdd(ans,elem);
            elem = strMul(elem,2);
        }
        cout<<ans<<endl;
    }
    return 0;
}

例题3——进制转换2(M进制---->N进制)

#include <iostream>
using namespace std;
/*
注意输入时如有字母,则字母为大写;
输出时如有字母,则字母为小写
*/
string strAdd(string str1,string str2){  //   十进制(没有前导0)  加法 认为str1是长度较长的那个
    if(str1.size()<str2.size()) swap(str1,str2);
    int len1=str1.size(),len2=str2.size(),carry=0,i,j;
    string res="";
    for(i=len1-1,j=len2-1;i>=0&&j>=0;i--,j--){
        carry += (str1[i]-'0') + (str2[j]-'0');
        char temp = (carry%10) + '0';
        res = temp + res;
        carry/=10;
    }
    while(i>=0){
        carry += (str1[i]-'0');
        char temp = (carry%10) + '0';
        res = temp + res;
        carry/=10;
        i--;
    }
    while(carry>0){
        char temp = (carry%10) + '0';
        res = temp + res;
        carry/=10;
    }
    int pos=0;
    while(pos<res.size()&&res[pos]=='0')
        pos++;
    if(pos==res.size()) return "0";
    return res.substr(pos);
}
string strMul(string str,int n){  //   十进制的乘法   n应该是一个较小的正整数
    int carry=0;
    string res="";
    for(int i=str.size()-1;i>=0;i--){
        carry += (str[i]-'0')*n;
        char temp = carry%10 + '0';
        res = temp + res;
        carry/=10;
    }
    while(carry>0){
        char temp = carry%10 + '0';
        res = temp + res;
        carry/=10;
    }
    int pos=0;
    while(pos<res.size()&&res[pos]=='0')
        pos++;
    if(pos==res.size()) return "0";
    return res.substr(pos);
}
string strDiv(string str,int n,int& mod){  //   十进制的除法   n应该是一个较小的正整数
    int remainder=0;
    string res="";
    char temp;
    for(int i=0;i<str.size();i++){
        remainder*=10;
        remainder+=str[i]-'0';
        temp = remainder/n +'0';
        res+=temp;
        remainder %= n;
    }
    mod = remainder;
    int pos=0;
    while(pos<res.size()&&res[pos]=='0')
        pos++;
    if(pos==res.size()) return "0";
    return res.substr(pos);
}
string TranFromX(string str,int x){   // 将x进制的数str转换为10进制数,先决条件:str是合法的x进制数
    string elem="1",res="0";
    for(int i=str.size()-1;i>=0;i--){
        int temp;
        if(str[i]>='A') temp=(str[i]-'A'+10);
        else temp=(str[i]-'0');
        res = strAdd(res,strMul(elem,temp));
        elem = strMul(elem,x);
    }
    int pos=0;
    while(pos<res.size()&&res[pos]=='0')
        pos++;
    if(pos==res.size()) return "0";
    return res.substr(pos);
}
string TranToX(string str,int x){   // 将10进制的数str转换为x进制数
    string res="";
    int mod;
    char temp;
    while(str!="0"){
        str=strDiv(str,x,mod);
        if(mod>9) temp=mod-10+'a';
        else temp = mod+'0';
        res=temp+res;
    }
    int pos=0;
    while(pos<res.size()&&res[pos]=='0')
        pos++;
    if(pos==res.size()) return "0";
    return res.substr(pos);
}
int main(){
    int M,N;
    while(cin>>M>>N){
        string input;
        cin>>input;
        cout<<TranToX(TranFromX(input,M),N)<<endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值