打印 1 到最大的 n 位数(使用字符串表示正数)

    打印 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;
}

 

转载于:https://my.oschina.net/u/2260265/blog/342072

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值