2022/5/29 第五次大作业 OurString, SuperInt
Problem 1 OurString
本题相当于string类的设计,注意内存的分配与删除,还有越界的问题即可,在此不做过多赘述。
不知道为什么,不用strncpy而是用strcpy的话它会提示有内存泄漏的可能性。但是按照qt提示使用strlcpy却提示没有这个函数,在visual studio里面试过,也没有。最后只能使用strncpy还要手动补零。
Problem 1 SuperInt
题目要求使用linked list(链表)来进行大整数的运算。
首先,使用list<int>储存每一位数字,另外单独定义一个int类型的sign来表示正负号。
题目要求至少重载 + 和 * ,而符号不同的加法又可以转化成减法,加上强迫症,所以我把加减乘除都重载了。
经过分析,两个数的加减法都可以缩小到 “正数 + 正数” 和 “大的正数 - 小的正数” 两种情况,所以只需要针对这两种情况进行计算。而由于减法和除法的需要,我重载了">"、"=="还有">="三个比较运算符,不过它们不会考虑符号,只比较绝对值的大小。
下面是代码
1 /* 2 * File: superint.h 3 * -------------- 4 * This interface exports the SuperInt class, which makes it possible to 5 * represent nonnegative integers of arbitrary magnitude 6 * on Assignment #5. 7 * [TODO: extend the documentation] 8 */ 9 10 #ifndef _superint_h 11 #define _superint_h 12 13 #include <string> 14 #include <iostream> 15 #include <list> 16 17 using namespace std; 18 19 enum SIGN{pos = 1, neg = -1}; 20 21 /* 22 * Implementation notes: SuperInt data structure 23 * ------------------------------------------- 24 * The SuperInt data structure stores the digits in the number in 25 * a linked list in which the digits appear in reverse order with 26 * respect to the items in the list. Thus, the number 1729 would 27 * be stored in a list like this: 28 * 29 * start 30 * +-----+ +-----+ +-----+ +-----+ +-----+ 31 * | o--+--->| 9 | ->| 2 | ->| 7 | ->| 1 | 32 * +-----+ +-----+ / +-----+ / +-----+ / +-----+ 33 * | o--+- | o--+- | o--+- | NULL| 34 * +-----+ +-----+ +-----+ +-----+ 35 * 36 * The sign of the entire number is stored in a separate instance 37 * variable, which is -1 for negative numbers and +1 otherwise. 38 * Leading zeros are not stored in the number, which means that 39 * the representation for zero is an empty list. 40 */ 41 42 class SuperInt { 43 44 public: 45 46 /* 47 * Constructor: SuperInt 48 * ----------------------- 49 * Usage: SuperInteger bi; 50 * Constructs a new big integer with default style; 51 */ 52 SuperInt(); 53 /* 54 * Constructor: SuperInt 55 * ----------------------- 56 * Usage: SuperInteger si1(si2); 57 * Constructs a new super integer whose value is a copy of another super integer. 58 */ 59 SuperInt(const SuperInt& s2); 60 /* 61 * Constructor: SuperInt 62 * Usage: SuperInt sup(str); 63 * ----------------------- 64 * Creates a new SuperInt from a string of decimal digits, 65 * which may begin with a minus sign to indicate a negative value. 66 */ 67 SuperInt(const char* s); 68 /* 69 * Constructor: SuperInt 70 * Usage: SuperInt sup(s); 71 * ----------------------- 72 * Creates a new SuperInt from a const string of decimal digits, 73 * which may begin with a minus sign to indicate a negative value. 74 */ 75 SuperInt(std::string str); 76 /* 77 * Constructor: SuperInt 78 * Usage: SuperInt sup(long); 79 * ----------------------- 80 * Creates a new SuperInt from a decimal long integer, 81 * which may begin with a minus sign to indicate a negative value. 82 */ 83 SuperInt(long n); 84 /* 85 * Destructor: ~SuperInt 86 * ------------------- 87 * Frees the memory used by a SuperInt when it goes out of scope. 88 */ 89 ~SuperInt(); 90 /* 91 * Method: toString 92 * Usage: string str = superint.toString(); 93 * -------------------------------------- 94 * Converts a SuperInt object to the corresponding string. 95 */ 96 std::string toString() const; 97 98 99 friend SuperInt operator+(const SuperInt& s1, const SuperInt& s2); 100 friend SuperInt operator-(const SuperInt& s1, const SuperInt& s2); 101 friend SuperInt operator*(const SuperInt& s1, const SuperInt& s2); 102 friend SuperInt operator/(const SuperInt& s1, const SuperInt& s2); 103 104 friend bool operator>(const SuperInt& s1, const SuperInt& s2); 105 friend bool operator==(const SuperInt& s1, const SuperInt& s2); 106 friend bool operator>=(const SuperInt& s1, const SuperInt& s2); 107 108 SuperInt& operator=(const SuperInt& s2); 109 friend ostream & operator<<(ostream &os, const SuperInt& s); 110 SuperInt abs(); 111 112 113 114 private: 115 list<int> lst; //本体 116 int sign = pos; //符号位 117 118 void removeZero(); //去掉首位的0 119 void carryPosSuperInt(); //进位函数 120 }; 121 122 #endif
1 /* 2 * File: superint.cpp 3 * ---------------- 4 * This file implements the superint.h interface 5 * on Assignment #5. 6 * [TODO: extend the documentation] 7 */ 8 9 #include <cctype> 10 #include <string> 11 #include<cstring> 12 #include<iostream> 13 #include<vector> 14 #include "superint.h" 15 #include "error.h" 16 using namespace std; 17 18 /* 19 * Implementation notes: SuperInt data structure 20 * ------------------------------------------- 21 * The SuperInt data structure stores the digits in the number in 22 * a linked list in which the digits appear in reverse order with 23 * respect to the items in the list. Thus, the number 1729 would 24 * be stored in a list like this: 25 * 26 * start 27 * +-----+ +-----+ +-----+ +-----+ +-----+ 28 * | o--+--->| 9 | ->| 2 | ->| 7 | ->| 1 | 29 * +-----+ +-----+ / +-----+ / +-----+ / +-----+ 30 * | o--+- | o--+- | o--+- | NULL| 31 * +-----+ +-----+ +-----+ +-----+ 32 * 33 * The sign of the entire number is stored in a separate instance 34 * variable, which is -1 for negative numbers and +1 otherwise. 35 * Leading zeros are not stored in the number, which means that 36 * the representation for zero is an empty list. 37 */ 38 39 SuperInt::SuperInt() 40 { 41 sign = pos; 42 } 43 44 SuperInt::SuperInt(const SuperInt& s2) //深拷贝 45 { 46 this->sign = s2.sign; 47 for(int i: s2.lst){ 48 this->lst.push_back(i); 49 } 50 removeZero(); 51 } 52 53 SuperInt::SuperInt(const char* s) //从最高位开始插 54 { 55 int i = 0; 56 if(s[0] == '-'){ 57 i = 1; 58 sign = neg; 59 } 60 for(; i < strlen(s); i++){ 61 lst.push_front(s[i] - '0'); 62 } 63 lst.push_back(0); //如果是空字符串,赋0 64 removeZero(); //防止非个位数前面有0 65 } 66 67 SuperInt::SuperInt(string str) //从最高位开始插 68 { 69 if(str[0] == '-'){ 70 sign = neg; 71 str = str.substr(1); 72 } 73 for(char ch: str){ 74 lst.push_front(ch); 75 } 76 lst.push_back(0); //如果是空字符串,赋0 77 removeZero(); //防止非个位数前面有0 78 } 79 80 SuperInt::SuperInt(long n) //从个位开始插 81 { 82 if(n < 0){ 83 sign = neg; 84 n *= -1; 85 } 86 while(n >= 10){ 87 lst.push_back(n % 10); 88 n /= 10; 89 } 90 lst.push_back(n); 91 } 92 93 SuperInt::~SuperInt() //默认析构 94 { 95 lst.clear(); 96 } 97 98 99 string SuperInt::toString() const 100 { 101 string str = ""; 102 103 for(int i: lst){ 104 char ch = i + '0'; 105 str = ch + str; //高位加在左边 106 } 107 if(sign == neg){ //带负号的话加上去 108 str = '-' + str; 109 } 110 if(str == "") str = "0"; //保险起见,加了这个 111 return str; 112 } 113 114 SuperInt SuperInt::abs(){ //取绝对值 115 if(sign == pos){ 116 return *this; 117 } 118 SuperInt s2; 119 s2 = *this; 120 s2.sign = pos; 121 return s2; 122 } 123 124 SuperInt operator+(const SuperInt& s1, const SuperInt& s2){ 125 SuperInt s3; 126 127 //若二者存在负数 128 if(s1.sign == neg && s2.sign != neg){ //负数加正数 129 SuperInt s4(s1); 130 s4.sign = pos; 131 return s2 - s4; 132 } 133 else if(s1.sign != neg && s2.sign == neg){ //正数加负数 134 SuperInt s4(s2); 135 s4.sign = pos; 136 return s1 - s4; 137 } 138 else if(s1.sign == neg && s2.sign == neg){ 139 s3.sign = neg; //两个负数相加 140 } 141 142 143 list<int>::const_iterator s1_it = s1.lst.begin(); 144 list<int>::const_iterator s2_it = s2.lst.begin(); 145 146 while(s1_it != s1.lst.end() && 147 s2_it != s2.lst.end()){ 148 int thisNum = *s1_it + *s2_it; //该位上的和 149 s3.lst.push_back(thisNum); //不管进位,就插 150 s1_it++; 151 s2_it++; 152 } 153 //到此,二者至少有一个为end() 154 155 if(s1_it != s1.lst.end()){ //看看是哪个先到end() 156 while(s1_it != s1.lst.end()){ 157 s3.lst.push_back(*s1_it); 158 s1_it++; 159 } 160 } 161 else{ //包含都到end()和s2到end()的情况 162 while(s2_it != s2.lst.end()){ 163 s3.lst.push_back(*s2_it); 164 s2_it++; 165 } 166 }//得到没有进位的s3 167 168 //s3开始进位 169 s3.carryPosSuperInt(); 170 return s3; //因为不可能出现首位为0的情况,所以不需要除0 171 } 172 173 SuperInt operator-(const SuperInt& s1, const SuperInt& s2){ 174 SuperInt s3; 175 176 if(s1.sign == neg && s2.sign == pos){//负数减正数 177 SuperInt s4(s2); 178 s4.sign = neg; 179 return s1 + s4; //转化成两个负数相加 180 } 181 else if(s1.sign == neg && s2.sign != pos){ //负数减负数 182 SuperInt s4(s2); 183 s4.sign = pos; 184 return s4 + s1; //转化为正数加负数 185 } 186 else if(s1.sign == pos && s2.sign == neg){ //正数减负数 187 SuperInt s4(s2); 188 s4.sign = pos; 189 return s1 + s4; //转化为两个正数相加 190 } 191 192 if(s2 > s1){ //如果被减数比减数小 193 s3 = s2 - s1; 194 s3.sign = neg; //符号为负 195 return s3; 196 } 197 198 //只负责正(大)数减正数(小) 199 list<int>::const_iterator s1_it = s1.lst.begin(); //从个位开始 200 list<int>::const_iterator s2_it = s2.lst.begin(); 201 202 while(s1_it != s1.lst.end() && 203 s2_it != s2.lst.end()){ 204 int thisNum = *s1_it - *s2_it; //该位上的差 205 s3.lst.push_back(thisNum); //不管进位,就插 206 s1_it++; 207 s2_it++; 208 } 209 //到此,二者至少有一个为end() 210 211 if(s1_it != s1.lst.end()){ //看看是哪个先到end() 212 while(s1_it != s1.lst.end()){ 213 s3.lst.push_back(*s1_it); 214 s1_it++; 215 } 216 } 217 else{ //包含都到end()和s2到end()的情况 218 while(s2_it != s2.lst.end()){ 219 s3.lst.push_back(*s2_it); 220 s2_it++; 221 } 222 }//得到没有进位的s3 223 224 //s3开始进位 225 list<int>::iterator s3_it = s3.lst.begin(); 226 while(s3_it != s3.lst.end()){ 227 if(*s3_it >= 0){ //不需要进位 228 s3_it++; 229 continue; 230 } 231 else{ 232 (*s3_it) += 10; //最多对高一位的数直接造成影响 233 234 s3_it++; 235 (*s3_it) -= 1; //退位 236 } 237 } 238 s3.removeZero(); 239 return s3; 240 } 241 242 SuperInt operator*(const SuperInt& s1, const SuperInt& s2){ 243 SuperInt s3; 244 //首先对符号进行操作 245 s3.sign = s1.sign * s2.sign; 246 247 //数字的部分 248 int carries = 0; 249 for(list<int>::const_iterator s1_it = s1.lst.begin(); s1_it !=s1.lst.end(); s1_it++){ 250 SuperInt s; 251 for(list<int>::const_iterator s2_it = s2.lst.begin(); s2_it !=s2.lst.end(); s2_it++){ 252 s.lst.push_back((*s1_it) * (*s2_it)); //模拟竖式乘法 253 } 254 s.carryPosSuperInt(); //可以最后再进位,但是防止出现超过int范围的情况 255 for(int i = 0; i < carries; i++){ 256 s.lst.push_front(0); //补位 257 } 258 259 s3 = s3 + s; 260 carries++; 261 } 262 263 s3.carryPosSuperInt();//保险起见,加一个 264 // s3.removeZero();//保险起见,加一个 265 266 return s3; 267 } 268 269 SuperInt operator/(const SuperInt& s1, const SuperInt& s2){//除法 270 SuperInt result("0"); 271 result.sign = s1.sign * s2.sign; 272 SuperInt s(s1); 273 while(s >= s2){ 274 result = result + 1; 275 s = s - s2; 276 } 277 return result; 278 } 279 280 bool operator>(const SuperInt& s1, const SuperInt& s2){ //注意!!!仅比较数字部分!!! 281 if(s1.lst.size() > s2.lst.size()){ 282 return true; 283 } 284 else if(s1.lst.size() == s2.lst.size()){ 285 list<int>::const_iterator s1_it = s1.lst.end(); 286 list<int>::const_iterator s2_it = s2.lst.end(); 287 while(s1_it != s1.lst.begin()){ 288 s1_it--; 289 s2_it--; 290 if(*s1_it > *s2_it){ 291 return true; 292 } 293 } 294 return false; 295 } 296 else{ 297 return false; 298 } 299 300 } 301 302 bool operator==(const SuperInt& s1, const SuperInt& s2){ //注意!!!仅比较数字部分!!! 303 if(s1.lst.size() != s2.lst.size()){ 304 return false; 305 } 306 list<int>::const_iterator s1_it = s1.lst.end(); 307 list<int>::const_iterator s2_it = s2.lst.end(); 308 while(s1_it != s1.lst.begin()){ 309 s1_it--; 310 s2_it--; 311 if(*s1_it != *s2_it){ 312 return false; 313 } 314 } 315 return true; 316 } 317 318 bool operator>=(const SuperInt& s1, const SuperInt& s2){ //注意!!!仅比较数字部分!!! 319 return s1 > s2 || s1 == s2; 320 } 321 322 SuperInt& SuperInt::operator = (const SuperInt& s2){ 323 lst.clear(); 324 this->sign = s2.sign; 325 for(int i: s2.lst){ 326 this->lst.push_back(i); 327 } 328 return *this; 329 } 330 331 ostream& operator << (ostream &os, const SuperInt& s){ 332 os << s.toString(); 333 return os; 334 } 335 336 void SuperInt::removeZero(){ //去0,如果最高位上有0就除去 337 while(lst.back() == 0 && lst.size() > 1){ //最高位为0 338 lst.pop_back(); 339 } 340 } 341 342 void SuperInt::carryPosSuperInt(){ //进位,将lst中的每一个数字都化为小于10的数字,然后进位 343 int times; 344 list<int>::iterator it = lst.begin(); 345 while(it != lst.end()){ 346 times = 0; 347 if(*it < 10){ //不需要进位 348 it++; 349 continue; 350 } 351 else{ 352 while(*it >= 10){ //算出进位数 353 (*it) -= 10; 354 times++; 355 } 356 357 it++; //进位 358 if(it == lst.end()){ 359 lst.push_back(times); 360 } 361 else{ 362 (*it) += times; 363 } 364 } 365 } 366 367 }
目前存在的疑问:
1.当superint类直接和数字相加减时,它不会报错,是不是因为重载了这些符号后,它会自动调用构造函数生成一个临时的superint变量再进行运算,所以才不会出错呢?

浙公网安备 33010602011771号