打印 1 到最大的 n 位数:输入数字 n 按顺序打印出从 1 最大的 n 为十进制数。例如,输入 3 , 打印 1, 2, ... , 999.
分析:注意没有规定 n 的范围,当 n 很大时,求最大的 n 位整数使用 int 或 long 类型都有可能会溢出。因此,最常用的解决方法是使用字符串或者是数组表达大数。
使用字符串表示的时候,最直观的方法就是使用字符 '0' ~'9' 之间的某一个字符来表示数字中的一位。因为数字最大是 n 位的,所以,需要一个 n + 1 的字符串(最后一个的符号位 '\0')。当实际数字不够 n 位时,在字符串的前半部分补零。
首先将字符串的每一位初始化为 '0',然后,每一次为字符串表示的数字加 1,在打印出来。因此,至于要做两件事:(一) 在字符串表达的数字上模拟加法,(二)把字符串表达的数字打印出来。
//主例程
void Print1ToMaxOfNDigits(int n)
{
if(n <= 0)
return;
char *number = new char[n + 1];
memset(number, '0', n);
number[n] = '\0';
while(!Increment(number))
{
PrintNumber(number);
}
delete [] number;
}
上述代码中,Increment()函数实现在表示数字的字符串 number 上增加 1 ;而函数 PrintNumber()打印出 number 。这两个看似简单的函数都暗藏着小小的玄机。
1) 需要知道在什么时候停止在 number 上加 1,一个最简单的办法就是每次递增之后,都调用库函数 strcmp()比较表示数字的字符串 number 和最大位数 n 位数字 “99...9”,如果想等表示已经到了最大的 n 位数并终止递增。虽然调用 strcmp 很简单,但对于长度为 n 的字符串,它的时间复杂度为 O(n)。
我们注意到只有在“99...9”加 1 的情况下,才会在第一个字符(下标为 0)的基础上产生进位,而其他所有的情况都不会在第一个字符上产生进位。因此,当我们发现加 1 在第一个字符上产生进位时,则已经是最大的 n 位数,此时,Increment 函数返回 true,函数 Print1ToMaxOfNDigits 中的while 循环终止。
以下代码实现了用 O(1) 的时间判断是否已经达到了最大的 n 位数:
bool Increment(char *number)
{
bool IsOverflow = false; //判断是否溢出(超出最大位数 n)
int nTakeOver = 0; //进位
int length = strlen(number);
for(int i = length - 1; i >= 0; i--)
{
int nSum = number[i] - '0' + nTakeOver;
if(i == length - 1)
nSum++; //每次调用数值增1
if(nSum >= 10)
{
if(i == 0)
IsOverflow = true; //在第一位字符处产生进位时,返回 true
else
{
nSum = nSum - 10;
nTakeOver = 1;
number[i] = '0' + nSum;
}
}
else
{
number[i] = '0' + nSum;
break;
}
}
return IsOverflow;
}
2)如何打印用字符串表示的数字:由于 当数字不够 n 位时,我们在数字的前面补零,打印时这些补位的 0 不应该打印出来,因此,不能简单的使用 printf 进行打印。为此,我们定义了函数 PrintNumber(),在这个函数里,只有在碰到第一个非零的字符时才开始打印,直到字符串的结尾。
void PrintNumber(char *number)
{
bool isBeginning0 = true;
int length = strlen(number);
for(int i = 0; i < length; i++)
{
if(isBeginning0 && number[i] != '0')
isBeginning0 = false;
if(!isBeginning0)
{
cout << number[i];
}
}
printf("\t");
}
总代码:
//打印 1 到最大的 n 位数
#include<iostream>
using namespace std;
bool Increment(char *number)
{
bool IsOverflow = false; //判断是否溢出(超出最大位数 n)
int nTakeOver = 0; //进位
int length = strlen(number);
//cout << length << endl;
for(int i = length - 1; i >= 0; i--)
{
int nSum = number[i] - '0' + nTakeOver;
if(i == length - 1)
nSum++; //每次调用数值增1
if(nSum >= 10)
{
if(i == 0)
IsOverflow = true;
else
{
nSum = nSum - 10;
nTakeOver = 1;
number[i] = '0' + nSum;
}
}
else
{
number[i] = '0' + nSum;
break;
}
}
return IsOverflow;
}
void PrintNumber(char *number)
{
bool isBeginning0 = true;
int length = strlen(number);
for(int i = 0; i < length; i++)
{
if(isBeginning0 && number[i] != '0')
isBeginning0 = false;
if(!isBeginning0)
{
cout << number[i];
}
}
printf("\t");
}
//主例程
void Print1ToMaxOfNDigits(int n)
{
if(n <= 0)
return;
char *number = new char[n + 1];
memset(number, '0', n);
number[n] = '\0';
while(!Increment(number))
{
PrintNumber(number);
}
delete [] number;
}
int main()
{
int n;
cin >> n;
Print1ToMaxOfNDigits(n);
cout << endl;
system("pause");
return 0;
}