一、代码
1.main.cpp
#include <iostream>
using namespace std;
#include "BigNumber.h"
#define MAX_RANGE 1000
#define TIME 10000
#define UNKNOWN -1
#define YES 1
CBigNumber next[TIME+5] = {0};
void init();
int caculate(int number);
void result(int number, int ret);
void setAllInNextTable(bool result);
int main()
{
for(int i = 1; i < MAX_RANGE; i++)
{
init();
int ret = caculate(i);
result(i, ret);
}
return 0;
}
void init()
{
memset(next, 0, sizeof(next));
}
int caculate(int number)
{
int cnt = 0;
CBigNumber temp(number);
int ret;
while((ret = temp.isLychrelNumber()) == UNKNOWN)
{
if(cnt > TIME)
{
ret = YES;
break;
}
temp.add();
next[cnt++] = temp;
}
return ret;
}
void result(int number, int ret)
{
if(ret == YES)
{
setAllInNextTable(false);
cout<<number<<endl;
}
else
{
setAllInNextTable(true);
}
}
void setAllInNextTable(bool result)
{
for(int i = 0; next[i].size != 0; i++)
{
next[i].setValue(result);
}
}
2.BigNumber.h
#define MAX_TABLE_SIZE 1000000
#define MAX_DIGIT 18
bool value[MAX_TABLE_SIZE] = {0};
bool isCaculated[MAX_TABLE_SIZE] = {0};
bool isReverse(long long number)
{
int word[10] = {0};
int cnt = 0;
while(number)
{
word[cnt++] = number % 10;
number /= 10;
}
for(int i = 0; i < cnt; i++)
{
if( word[i] != word[cnt - i - 1])
{
return false;
}
}
return true;
}
bool isAllDigitSmallerThan5(long long number)
{
while(number)
{
int last = number % 10;
if(last >= 5)
return false;
number /= 10;
}
return true;
}
int isLychrelNumber(long long number)
{
if(isReverse(number) == true)
return 0;
if(isAllDigitSmallerThan5(number) == true)
return 0;
if(number >= MAX_TABLE_SIZE || isCaculated[number] == false)
return -1;
return !value[number];
}
#define MAX_SIZE 200
class CBigNumber
{
private:
long long data[MAX_SIZE];
bool isNumberTooBig();
bool isReverse();
bool isAllDigitSmallerThan5();
bool isInRecord();
public:
int size;
CBigNumber();
CBigNumber(const CBigNumber &B);
CBigNumber(long long normalData);
int isLychrelNumber();
void add();
void setValue(bool flag);
void print();
CBigNumber &operator=(const CBigNumber & B);
bool operator==(const CBigNumber & B);
CBigNumber getReverseNumber();
};
CBigNumber::CBigNumber()
{
size = 0;
memset(data, 0, sizeof(data));
}
CBigNumber::CBigNumber(const CBigNumber &B)
{
size = B.size;
for(int i = 0; i < B.size; i++)
data[i] = B.data[i];
}
CBigNumber::CBigNumber(long long normalData)
{
memset(data, 0, sizeof(data));
data[0] = normalData;
size = 1;
}
int CBigNumber::isLychrelNumber()
{
if(size == 1)
return ::isLychrelNumber(data[0]);
if(isNumberTooBig() == true)
return 1;
if(isReverse() == true)
return 0;
if(isAllDigitSmallerThan5() == true)
return 0;
if(isInRecord() == false)
return -1;
return !value[data[0]];
}
void CBigNumber::add()
{
CBigNumber reverse = getReverseNumber();
for(int i = 0; i < size; i++)
{
data[i] = data[i] + reverse.data[i];
if(data[i] > 1000000000000000000)
{
data[i] = data[i] - 1000000000000000000;
data[i+1]++;
}
}
if(data[size] > 0)
size++;
}
void CBigNumber::setValue(bool flag)
{
if(size == 1 && data[0] < MAX_TABLE_SIZE)
{
isCaculated[data[0]] = true;
value[data[0]] = flag;
}
}
void CBigNumber::print()
{
for(int i = 0; i < size; i++)
cout<<data[i];
}
CBigNumber& CBigNumber::operator=(const CBigNumber & B)
{
size = B.size;
for(int i = 0; i < size; i++)
data[i] = B.data[i];
return *this;
}
bool CBigNumber::operator==(const CBigNumber & B)
{
if(size != B.size)
return false;
for(int i = 0; i < size; i++)
if(data[i] != B.data[i])
return false;
return true;
}
bool CBigNumber::isNumberTooBig()
{
if(size >= MAX_SIZE)
return true;
return false;
}
bool CBigNumber::isReverse()
{
CBigNumber reverse = getReverseNumber();
if(reverse == *this)
return true;
else
return false;
}
bool CBigNumber::isAllDigitSmallerThan5()
{
for(int i = 0; i < size; i++)
if(::isAllDigitSmallerThan5(data[i]) == false)
return false;
return true;
}
bool CBigNumber::isInRecord()
{
if(size > 1)
return false;
if(data[0] >= MAX_TABLE_SIZE)
return false;
return isCaculated[data[0]];
}
CBigNumber CBigNumber::getReverseNumber()
{
CBigNumber ret;
int digit[10000] = {0}, start;
for(int i = 0; i < size; i++)
{
start = i * 18;
long long temp = data[i];
while(temp)
{
digit[start++] = temp % 10;
temp = temp / 10;
}
}
memset(ret.data, 0, sizeof(ret.data));
for(int i = 0; i < start; i+=18)
{
for(int j = i; j < i+18; j++)
{
if(j >= start)break;
ret.data[ret.size] = ret.data[ret.size] * 10 + digit[j];
}
ret.size++;
}
return ret;
}
二、评论
1.main.cpp逻辑太复杂
2.不应该在.h中写实现代码
3.int CBigNumber::isLychrelNumber()函数太长,其中的判断不在一个逻辑层次
4.isNumberTooBig()优化效果不明显,却严重影响代码阅读,建议去掉
5.Record是对中间过程的缓存,建议更名为buffer
6.部分魔应定义为宏
7.垂直的函数顺序不好,应参考《代码简洁之道》5.2.3和5.2.5
8.部分命名需要重新设计