编程珠玑第三章习题答案

1 税收问题

.if-else语句的每个分支的形式都差不多,我们可以用数组来使循环简单一点。数组中每个点表明一个阶段,用level[i]表示阶段i的起始点,tax[i]表示阶段i的税率。然后就是输入一个收入,利用二分搜索找到一个最接近于这个收入的税率计算的分段点,当然也可以不用二分搜索找到这个分段点。

int level[100] = { 2200, 2700, ....}

double taxi[100] = {0, 0.14, 0.15, 0.16, ...}

  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. using namespace std;  
  4.   
  5. int binarysearch(int start, int end, int find, int* a);  
  6. int main(int argc, char* argv[])  
  7. {  
  8.     int lower_limit[40];  
  9.     int iter;  
  10.     int find;  
  11.   
  12.     for(int i = 0; i < 40; i++) //初始化下限数组  
  13.     {  
  14.         lower_limit[i] = 2200 + i * 500;   
  15.     }  
  16.     cin >> find;  
  17.     while(find != -1)  
  18.     {  
  19.         iter = binarysearch(0,39,find,lower_limit);  
  20.         cout << lower_limit[iter] <<endl;  
  21.         cin >> find;  
  22.     }  
  23.         return 0;   
  24. }  
  25. int binarysearch(int start, int end, int find, int* a)  
  26. {  
  27.     int mid;  
  28.     if(start == end)  
  29.         return end;  
  30.     else   
  31.     {  
  32.         mid = (start + end)/2;  
  33.         if(find <= a[mid])  
  34.             return(binarysearch(start,mid,find,a));  
  35.         else  
  36.             return(binarysearch(mid+1,end,find,a));   
  37.     }  
  38. }   

可以通过观察法,找规律确定税率的分段点。

其实观察书中下限的数据为2200,2700,3200,3700.........

就是2200+i*500

那么只要将要找的数据find: 

  iter = (find-2200)/500;

  if((find-2200)%500 == 0)

return iter;

  else 

return iter +1;

就可以了,不用搜索。找到这个分段点了之后就可以计算税收了:

假定找到的这个最接近的分段点是iter,如果不是在第一个分段点内,那么taxresult=(level[iter-1]-2200)*taxi[iter-1]+(income-level[iter-1])*taxi[iter]

3、编写标语函数,输入一个大写字母,输出一个字符数组,该字符数组用字符图形方式描绘该字母

这题不大懂,百度了下答案,发现答案的重点在于将26个字母用特定的表示方式表示出来,可以考虑为字母的外形设计一个定制模板,自己规定一套模板编写的格式,然后写一个解析程序,每次打印字母时,只需解析字母对应的模板即可,这样主要的工作量就花在每个字母模板的编写上,当然模板的编写是相当简单的,将字母图形转化为相应的模板格式即可。例如

xxxxxxxxx
xxxxxxxxx
xxxxxxxxx
   xxx   
   xxx   
   xxx   
   xxx   
   xxx   
   xxx   
xxxxxxxxx
xxxxxxxxx
xxxxxxxxx
这个I可以用39x,63b3x3b,39x 表示。

这个方法倒是提醒了我一些当遇到复杂的表示方法时,可以找出这个复杂方法的共性,然后用简单的表现形式代替复杂的表现形式,最后只要通过解析简单的表现形式即可。

4.有意思的题:给定两个日期,计算两者之间的天数;给定一个日期,返回值为周几;给定月和年,使用字符数组生成该月的日历

先看下关于题目背景的科普知识:

问题的提出:日历的编排是每400年一个大循环周期,即今年的月、日、星期几和400年前的完全一样。现行天文历法根据天体运行规律,取每年365.2425天。这样,每400年共有365.2425×400=146097天。如果以365天作为一年,每400年就少了0.2425×400=97天。这97天要靠设置闰年(每年366)天来凑齐,所以,每400年要设置97个闰

判断闰年的方法:

判断闰年一般的规律为: 四年一闰,百年不闰,四百年再闰。其简单计算方法:1。能被4整除而不能被100整除。(如2004年就是闰年,1800年不是。)2。能被400整除。(如2000年是闰年)
判断星期几的方法:(以1900作为参考)

参考:http://blog.163.com/shadow_hier/blog/static/4051874220095873612503/

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <iostream>   
  4. int monthdays[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};  
  5. typedef struct   
  6. {  
  7.     int year;  
  8.     int month;  
  9.     int day;  
  10. }Date;  
  11. //判断是否是闰年  
  12. bool isrunyear(Date *date)  
  13. {  
  14.     if(((date->year%4==0) && (date->year%100!=0))  
  15.         || (date->year % 400) == 0)  
  16.         return true;  
  17.     return false;  
  18. }  
  19. //计算某个日期是一年中的第几天  
  20. int yearday(Date *date)  
  21. {  
  22.     int total = 0;  
  23.     for(int i = 1; i < date->month; i++)  
  24.     {  
  25.         total+=monthdays[i];  
  26.     }  
  27.     if(date->month > 2 && isrunyear(date))  
  28.     {  
  29.         total+=1;  
  30.     }  
  31.     return total+date->day;  
  32. }  
  33. //计算两个日期之间的天数间隔(date2 晚于 date1)  
  34. int betweenday(Date *date1, Date *date2)  
  35. {  
  36.     if(date1->year == date2->year)  
  37.         return yearday(date2) - yearday(date1);  
  38.     else  
  39.     {  
  40.         int totaldays = 0;  
  41.         for(int i = date1->year; i < date2->year; i++)  
  42.         {  
  43.             Date d;  
  44.             Date *date;  
  45.             date = &d;  
  46.             d.year = i;  
  47.             totaldays+=isrunyear(date)?366:365;  
  48.         }  
  49.   
  50.         return totaldays - yearday(date1) + yearday(date2);   
  51.     }  
  52.       
  53. }  
  54. //判断某日子属于一周中第几天  
  55. int weekday(Date *date)  
  56. {  
  57.     Date d;  
  58.     Date *d1;  
  59.     d1 = &d;  
  60.     d.year = 1900;  //选取1900年作为参考,日历都是以1900为参考的,1900.1.1为星期一,其它日期相对它的天数与7取余                     //数再加上1就是对应的星期几。这里用1~7表示星期一到星期天
  61.     d.month = 1;  
  62.     d.day = 1;  
  63.     return betweenday(d1,date)%7+1;  
  64. }  
  65. //输出某年某月日历  
  66. void printyearmonth(Date *date)  
  67. {  
  68.     printf("%d年%d月\n",date->year,date->month);  
  69.     printf("日 一 二 三 四 五 六\n");  
  70.     date->day = 1;  
  71.     int first = weekday(date);  
  72.     int i;  
  73.     if(first != 7)  
  74.     {     
  75.         //先输出1号前面的空白  
  76.         for(i = 0; i < first; i++)  
  77.         {  
  78.             printf("   ");  
  79.         }  
  80.         //输出1号后非空白部分  
  81.         for(i = 1; i <= 7 - first; i++) //把第一周的情况不全,从first开始的星期几到星期天 
  82.         {  
  83.             printf("%-3d",i);  
  84.         }  
  85.         printf("\n");  
  86.     }  
  87.     //计算该月总天数  
  88.     int monthday = (date->month==2)?(isrunyear(date)?29:28):monthdays[date->month];  
  89.       
  90.     for(i = 8 - first; i <= monthday; i++)  
  91.     {  
  92.         printf("%-3d",i);  
  93.         if(i % 7 == 7 - first)  
  94.             printf("\n");  
  95.     }  
  96.     printf("\n");  
  97. }  
  98. int getlength(char *a)  
  99. {  
  100.     return 0;  
  101. }  
  102.   
  103.   
  104. void main()  
  105. {  
  106.     Date d1;  
  107.     Date *date1;  
  108.     date1 = &d1;  
  109.     d1.year = 2011;  
  110.     d1.month = 2;  
  111.     d1.day = 1;  
  112.     Date d2;  
  113.     Date *date2;  
  114.     date2 = &d2;  
  115.     date2->year = 2013;  
  116.     date2->month = 4;  
  117.     date2->day = 5;  
  118.     printf("%d\n", betweenday(date1,date2));  
  119.     printf("%d\n", weekday(date2));  
  120.     printyearmonth(date1);  
  121.   
  122. }  

5、查找后缀连字符的连接

因为这里要确定的是输入单词中是否有规则中的后缀,因为是后缀所以尾部一定要完全一样才可以。所以这里对于单词的比较是从右到左的比进行的。所以最开始的时候需要把规则中的后缀都全部翻转了,同时对于输入的单词也需要进行翻转。另外这里保存规则中的字符数组的时候可以采用多种方法。如果是采用二维字符数组,那么会比较浪费空间,最好是用带有单词指针数组的字符数组来保存。

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <iostream>   
  4. char *p[] = {"et-ic""al-is-tic""s-tic""p-tic""-lyt-ic""ot-ic""an-tic",  
  5. "n-tic""c-tic""at-ic""h-nic""n-ic""m-ic""l-lic""b-lic""-clic""l-ic",  
  6. "h-ic""f-ic""d-ic""-bic""a-ic""-mac""i-ac"}; //带有单词指针的字符数组
  7. //返回后缀连字符连接  
  8. int getlastsamechar(char* a)  //a就是输入的某个单词,判断a中是否包含了规则中的合法连字符的情况
  9. {  
  10.     int result = -1;  
  11.     //先将后缀字符数组每项反转  
  12.     int i = 0;  
  13.     int j = 0;  
  14.     int alen = strlen(a);  
  15.     char* aswap = new char[alen + 1];  
  16.     strcpy(aswap, a);  
  17.     for(i = 0; i < alen/2; i++)  
  18.     {  
  19.         char c = aswap[i];  
  20.         aswap[i] = aswap[alen - 1 - i];  
  21.         aswap[alen - 1 - i] = c;  
  22.     }  
  23.     printf("%s\n",aswap);  
  24.     int n = sizeof(p)/sizeof(char*);  //规则中连字符共有n个
  25.     for(i = 0; i < n; i++)  
  26.     {  
  27.         int len = strlen(p[i]);  
  28.         char* b = new char[len+1];  
  29.         strcpy(b,p[i]);  
  30.         //去掉字符串里的-  
  31.         for(j = 0; j < len; j++)  //翻转某个连字符
  32.         {  
  33.             if(b[j] == '-')  
  34.             {  
  35.                 for(int q = j; q < len; q++)  
  36.                 {  
  37.                     b[q] = b[q+1];  
  38.                 }  
  39.                 len--;  
  40.             }  
  41.         }  
  42.         for(j = 0; j < len/2; j++)  
  43.         {  
  44.             char c = b[j];  
  45.             b[j] = b[len - 1 - j];  
  46.             b[len - 1- j] = c;  
  47.         }  
  48.         if(alen >= len)  
  49.         {  
  50.             for(j = 0; j < len; j++)  
  51.             {  
  52.                 if(aswap[j] != b[j])  
  53.                 {  
  54.                     break;  
  55.                 }                 
  56.             }  
  57.             delete b;  
  58.             if(j == len)  
  59.             {  
  60.                 result = i;  //找到输入的字符串a中有的p中的第i个连字符
  61.                 break;  
  62.             }  
  63.         }  
  64.   
  65.     }  
  66.     delete aswap;  
  67.     return result;  
  68. }  
  69. void main()  
  70. {  
  71.     char *a = "clinic";  
  72.     int result = getlastsamechar(a);  
  73.     printf("%d\n",result);  
  74.     if(-1 != result)  
  75.     {  
  76.         char* res = new char[strlen(p[result]) + 1];  
  77.         strcpy(res, p[result]);  
  78.         printf("%s\n", res);  //输出字符串a中存在的那个连字符
  79.     }  
  80.   
  81.   
  82. }  
8、获取数码管显示方式

把7段显示用7bit来表示。

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <iostream>   
  4. //数字0-9的数码管显示方式  
  5. char *number[] = {"1011111","0000101","1110110","1110101","0101101",  
  6.     "1111001","1111011","0010101","1111111","1111101"};//从左往右数分别是数码管的七段显示的标号1~7  
  7. //获取16bit的正整数  
  8. char** getNumber(int bit)  
  9. {  
  10.     char** result= new char*[5];  
  11.     for(int i = 4; i >= 0; i--)  
  12.     {  
  13.         result[i] = number[bit%10];//计算这个五位数的一位,对应就是其在number数组中的标号,直接从number数组中就可                                    //以获取数字的数码管显示方式。
  14.         bit/=10;  
  15.     }  
  16.     return result;  
  17. }  
  18. void main()  
  19. {  
  20. char** num = getNumber(54673);  
  21.     for(int i = 0; i < 5; i++)  
  22.     {     
  23.         printf("%s\n",*num);  
  24.         num++;  
  25.     }  






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值