C++中超长整型类型的构造与实现(附源码)
2014-08-02 17:32
344 查看
在曾经的一次面试经历中,被问到这样的问题:如何处理长度有几十位甚至上百位整型数字的加减法?
这是个很有意思的问题,当时我并没能给出令人满意的答案,但这个问题一直围绕在我的脑海,至今,我想把它实现一下。其实这个问题的难度已经被有意的缩减了,因为这里只说到加减法,如果要用到乘除法,那可能会更为麻烦一点,这是其一。其二,没有涉及小数位。那么下面我们就先来实现超长整型的加减法吧。
(注:在写本篇学习笔记时,本人学习和参考了网络文章,并做了借鉴,感谢各位前辈的分享。如果本文对您有所帮助,您可以随意分享,如果发现文中有误,也请指教,谢谢。本文用到的调试工具:Microsoft Visual Studio
10,操作系统:Windows 7)
在进行加减法运算的时候,首先判断两个操作数的符号位,若为同号,则用加法,若为异号,则用减法。
为了满足基本类型中从个位开始相加的方法,首先将两个超长整型中的m_strData中的字符串反转,从字符串的第一位开始相加,最后又将结果反转还原。比如对于操作数“723456”+“76912”,首先反转为“654327”+“21967”,再从字符串的第一位相加,并且向右进位,得到结果为“863008”,最后反转还原为“800368”。
综上所述,我们需要的数据成员有:符号位、数据长度、数值。
需要用到的方法有:加法函数、减法函数、字符串反转函数,还需要重载“+”、“-”,还可以重载输入输出流“<<”、“>>”。
最后再加上一些需要用到的其他方法,头文件VeryLong.h的定义如下:
由于涉及正负数,所以两个操作数的相加在运算过程中不一定是相加,如果符号不一样,那就只能使用相减运算。这也是我把加减函数和重载运算符“+”、“-”分开的原因。
在做减法运算的之前,如果我们事先知道两个操作符的大小,那我们在运算的时候就会省很多事,所以我们希望在进入sub()函数之前,比较出大小,并且约定大在前小在后。
所以,重载运算符中的实现如下:
函数plus()的实现如下:
函数sub()的实现如下:
至此,一些主要函数的实现都已经在上面了,最后,贴出辅助函数的实现。
函数reversalStr()的实现如下:
函数setData()的实现如下:
重载运算符函数ostream &operator<<()的实现如下:
三个构造函数的定义如下:
析构函数的实现如下:
这是个很有意思的问题,当时我并没能给出令人满意的答案,但这个问题一直围绕在我的脑海,至今,我想把它实现一下。其实这个问题的难度已经被有意的缩减了,因为这里只说到加减法,如果要用到乘除法,那可能会更为麻烦一点,这是其一。其二,没有涉及小数位。那么下面我们就先来实现超长整型的加减法吧。
(注:在写本篇学习笔记时,本人学习和参考了网络文章,并做了借鉴,感谢各位前辈的分享。如果本文对您有所帮助,您可以随意分享,如果发现文中有误,也请指教,谢谢。本文用到的调试工具:Microsoft Visual Studio
10,操作系统:Windows 7)
在进行加减法运算的时候,首先判断两个操作数的符号位,若为同号,则用加法,若为异号,则用减法。
为了满足基本类型中从个位开始相加的方法,首先将两个超长整型中的m_strData中的字符串反转,从字符串的第一位开始相加,最后又将结果反转还原。比如对于操作数“723456”+“76912”,首先反转为“654327”+“21967”,再从字符串的第一位相加,并且向右进位,得到结果为“863008”,最后反转还原为“800368”。
综上所述,我们需要的数据成员有:符号位、数据长度、数值。
需要用到的方法有:加法函数、减法函数、字符串反转函数,还需要重载“+”、“-”,还可以重载输入输出流“<<”、“>>”。
最后再加上一些需要用到的其他方法,头文件VeryLong.h的定义如下:
#pragma once #include <iostream> #include <string> #include <cstring> using namespace std; #define NUM_LEN 1000 class CVeryLong { public: CVeryLong(void); CVeryLong(const char * sData); CVeryLong(const CVeryLong &other); ~CVeryLong(void); int getLen(); int getSign(); char * getData(); void setData(const char * sData); static int bigNum(const int a, const int b);/* 比较a、b大小 */ static void plus(CVeryLong &cvl, CVeryLong &c1, CVeryLong &c2); static void sub(CVeryLong &cvl, CVeryLong &c1, CVeryLong &c2); friend CVeryLong operator+(CVeryLong &c1, CVeryLong &c2); friend CVeryLong operator-(CVeryLong &c1, CVeryLong &c2); friend istream &operator>>(istream &in, CVeryLong &c); friend ostream &operator<<(ostream &out, CVeryLong &c); private: void reversalStr();/* 字符串反转 */ void setLen(const int &iLen); void setSign(const int &iSign); int m_iSign; /* 符号位:1-负号 0-正号 */ int m_iLen; /* 字符串长度 */ char * m_sData; /* 字符串值 */ };
由于涉及正负数,所以两个操作数的相加在运算过程中不一定是相加,如果符号不一样,那就只能使用相减运算。这也是我把加减函数和重载运算符“+”、“-”分开的原因。
在做减法运算的之前,如果我们事先知道两个操作符的大小,那我们在运算的时候就会省很多事,所以我们希望在进入sub()函数之前,比较出大小,并且约定大在前小在后。
所以,重载运算符中的实现如下:
CVeryLong operator+(CVeryLong &c1, CVeryLong &c2) { CVeryLong cvl; if (c1.getSign() == c2.getSign()) { CVeryLong::plus(cvl,c1,c2); } else { if (c1.getLen()>c2.getLen()) { CVeryLong::sub(cvl,c1,c2); } else if(c1.getLen()<c2.getLen()) { CVeryLong::sub(cvl,c2,c1); } else { if (strcmp(c1.getData(),c2.getData()) > 0) { CVeryLong::sub(cvl,c1,c2); } else if (strcmp(c1.getData(),c2.getData()) > 0) { CVeryLong::sub(cvl,c2,c1); } else { cvl.setData("0"); } } } return cvl; }如开篇所说,在加减法运算过程中,我们可以先把操作数中的字符串反转,然后从第一位开始做加减运算,并且向右进位或者借位。在两个字符进行加减运算的时候,我们可以运用字符可自动转换成ASCII码直接进行加减,并且赋值给一个整形变量即可,当然我们知道0~9的ASCII码表对应的是48~57,所以要对操作数进行处理之后再做加减。
函数plus()的实现如下:
void CVeryLong::plus(CVeryLong &cvl, CVeryLong &c1, CVeryLong &c2) { int i=0; int j=0; int ver=0; char ch='0'; char ch0='0'; char ch1='\0'; char ch2='\0'; char str[NUM_LEN]={0}; c1.reversalStr(); c2.reversalStr(); j=CVeryLong::bigNum(c1.getLen(),c2.getLen()); for(i=0;(i<c1.getLen() || i<c2.getLen()) || (i==j && ch=='1');i++) { if (i<c1.getLen()) { ch1=c1.m_sData[i]; } else { ch1='0'; } if (i<c2.getLen()) { ch2=c2.m_sData[i]; } else { ch2='0'; } ver=(ch1-ch0)+(ch2-ch0)+(ch-ch0); if(ver>9) { ch='1'; ver=ver-10; } else { ch='0'; } sprintf_s(str,NUM_LEN,"%s%d",str,ver); } cvl.setData(str); cvl.setSign(c1.getSign()); cvl.reversalStr(); c1.reversalStr(); c2.reversalStr(); }
函数sub()的实现如下:
void CVeryLong::sub(CVeryLong &cvl, CVeryLong &c1, CVeryLong &c2) { int i=0; int j=0; int ver=0; char ch='0'; char ch0='0'; char ch1='\0'; char ch2='\0'; char str[NUM_LEN]={0}; c1.reversalStr(); c2.reversalStr(); j=CVeryLong::bigNum(c1.getLen(),c2.getLen()); for(i=0;(i<c1.getLen() || i<c2.getLen());i++) { if (i<c1.getLen()) { ch1=c1.m_sData[i]; } else { ch1='0'; } if (i<c2.getLen()) { ch2=c2.m_sData[i]; } else { ch2='0'; } ver=(ch1-ch0)-(ch2-ch0)-(ch-ch0); if(ver<0) { ch='1'; ver=ver+10; } else { ch='0'; } sprintf_s(str,NUM_LEN,"%s%d",str,ver); } cvl.setData(str); cvl.setSign(c1.getSign()); cvl.reversalStr(); c1.reversalStr(); c2.reversalStr(); }
至此,一些主要函数的实现都已经在上面了,最后,贴出辅助函数的实现。
函数reversalStr()的实现如下:
void CVeryLong::reversalStr() { char c; for(int i=0;i<m_iLen/2;++i) { c=m_sData[i]; m_sData[i]=m_sData[m_iLen-i-1]; m_sData[m_iLen-i-1]=c; } }
函数setData()的实现如下:
void CVeryLong::setData(const char * sData) { if (sData==m_sData) { return; } if (NULL != m_sData) { delete []m_sData; } m_iSign=0; m_iLen=0; const char * tmp=NULL; if (NULL == sData) { m_iSign=0; m_iLen=0; m_sData=new char[1]; *m_sData='\0'; } else { tmp=sData; if (strncmp(sData,"-",1)==0) { m_iSign=1; sData++; } else if (strncmp(sData,"+",1)==0) { m_iSign=0; sData++; } m_iLen=strlen(sData); m_sData=new char[m_iLen+1]; strcpy(m_sData,sData); sData=tmp; } }
重载运算符函数ostream &operator<<()的实现如下:
ostream &operator<<(ostream &out, CVeryLong &c) { if (c.getSign() == 1) { out<<"-"; } out<<c.m_sData; return out; }
三个构造函数的定义如下:
CVeryLong::CVeryLong(void) { m_iSign=0; m_iLen=0; m_sData=new char[1]; *m_sData='\0'; }
CVeryLong::CVeryLong(const char *sData) { const char * tmp=NULL; if (NULL == sData) { m_iSign=0; m_iLen=0; m_sData=new char[1]; *m_sData='\0'; } else { tmp=sData; if (strncmp(sData,"-",1)==0) { m_iSign=1; sData++; } else if (strncmp(sData,"+",1)==0) { m_iSign=0; sData++; } else { m_iSign=0; } m_iLen=strlen(sData); m_sData=new char[m_iLen+1]; strcpy(m_sData,sData); sData=tmp; } }
CVeryLong::CVeryLong(const CVeryLong &other) { if (&other==this) { return; } m_iSign=other.m_iSign; m_iLen=other.m_iLen; m_sData=new char[m_iLen+1]; strcpy(m_sData,other.m_sData); }
析构函数的实现如下:
CVeryLong::~CVeryLong(void) { m_iSign=0; m_iLen=0; delete []m_sData; }
相关文章推荐
- C++模拟实现Objective-C动态类型(附源码)
- 较高人工智能的人机博弈程序实现(多个算法结合)含C++源码
- 较高人工智能的人机博弈程序实现(多个算法结合)含C++源码
- 为什么C++里所有类型的变量都一整型输出???请高手帮忙, 谢谢啦!!!!
- 自动打开“我的电脑“ C++源码实现
- “基于关键字匹配的文本过滤系统”配置文件的设计和实现(C/C++源码)
- GoF 23种设模式解析附C++实现源码(k_eckel转自微软高校博客K_eckel's mindview)
- 整型映射和类型映射(节选自《Modern C++ Design》)
- Contourlet变换的C++源码的实现
- C++实现文件操作(源码)!
- 一组实现邮件发送功能的c++封装类(附源码)
- C++模板应用——在类模板实现中引用其内部定义的复合数据类型
- stand C++ stack 的实现源码
- 较高人工智能的人机博弈程序实现(多个算法结合)含C++源码
- 类型转换的实现代码(C++)
- 较高人工智能的人机博弈程序实现(多个算法结合)含C++源码
- 在c++中如何实现非consle类型的计时器
- 较高人工智能的人机博弈程序实现(多个算法结合)含C++源码
- 构造数据类型(C++)
- 【C++】栈——顺序表实现V1.0(源码提供)