【编程珠玑】第三章:数据结构程序

第一题

问题:有一段编程代码给出了25个if语句,作为一个合理的方法来计算1978年美国联邦所得税。比率序列0.14,0.15,0.16,0.17,0.18,...序列每次增加0.01。请对此作出评价。

解答:这是一段比较糟糕的代码。事实上,应该先挖掘规律再用for循环代替冗长的代码。先看税收比率,每次增加0.1,再看阶梯,每500元就一个新的比率。

/***********************************************************/
// 程序目的:税收计算
// 日期:    2014-09-02 
// 作者:    spencer_chong
// 邮箱:    zhuangxb91@qq.com
/***********************************************************/
#include <iostream>

using namespace std;
//用递归的方法
int compute(int income,int baseline,int i)
{
	if (income<=2200)
		return 0;
	
	return (income-baseline)*(0.13+0.01*i)+compute(baseline,baseline-500,i-1);
}

int main()
{
	int income;
	int baseline = 2200;
	int tax;
	int i;
	cout<<"请输入收入:"<<endl;
	cin>>income;
	
	i=(income-2200)/500;
	baseline = 2200+500*i;
	tax = compute(income,baseline,i+1);
	cout<<tax<<endl;
	return 0;
	
}
请输入收入:
3300
161
请按任意键继续. . .

第二题

问题:第k阶常数线性递归定义了一个序列如下所示,a(n)=c(1)a(n-1)+c(2)a(n-2)+c(3)a(n-3)+...+c(k)a(n-k)+c(k+1),这里c(1),c(2),...,c(k+1)是实数。请编写一个程序,输入k,a(1),a(2),...,a(k),c(1),c(2),...c(k+1)和m,输出a(1),a(2),...,a(m).与对一个特定的50阶递归进行求值并且不适用数组的程序相比,请问该程序有何难度?

解答:不大理解题目意思,感觉挺无聊的。

/***********************************************************/
// 程序目的:多项式求值
// 日期:    2014-09-02 
// 作者:    spencer_chong
// 邮箱:    zhuangxb91@qq.com
/***********************************************************/
#include <iostream> 
using namespace std; 
 
int main() 
{ 
    int t=0; 
    int i,k; 
    int  n=10; 
    int c[10]={1,2,3,4,5,6,7,8,9,10}; 
    int a[10]={0}; 
    for(k=1;k<n;++k) 
    { 
        for(i=1;i<k;++i) 
            a[k] = a[k-i] * c [i]; 
 
        a[k] +=c[k+1]; 
    } 
    for(i=0;i<n;++i) 
        cout<<a[i]<<endl; 
     
    return 0; 
} 
请输入收入:
3300
161
请按任意键继续. . .

第三题

问题:请编写一个“banner(标语)”函数,输入一个大写字母,输出一个字符数组,该字符数组用图形方式描绘该字母。

解答:(答案来自互联网)对于26个字母,每个字母的外形并没有必然规律可循,最直接的方法是编写26个函数,针对特定的字母编写特定的打印程序,这是个体力活,代码数量将非常巨大。联想上面的格式信函编程,可以考虑为字母的外形设计一个定制模板,自己规定一套模板编写的格式,然后写一个解析程序,每次打印字母时,只需解析字母对应的模板即可,这样主要的工作量就花在每个字母模板的编写上,当然模板的编写是相当简单的,将字母图形转化为相应的模板格式即可。例如: 一个字母可以利用length = 12, width = 9的矩阵来表示。任何字母都可以在这张表示出来,每个点就像一个像素点。下面就对字母I进行模板编码,编码要求
(1)用尽可能简单的方式表示上面的图像;
(2)方便程序解析;
(3)必须适用于所有的情况

x  x  x  x  x  x  x  x  x
x  x  x  x  x  x  x  x  x
x  x  x  x  x  x  x  x  x
         x  x  x        
         x  x  x        
         x  x  x        
         x  x  x        
         x  x  x        
         x  x  x        
x  x  x  x  x  x  x  x  x
x  x  x  x  x  x  x  x  x
x  x  x  x  x  x  x  x  x

第四题

问题:请编写处理下列时间问题的函数:给定两个日子,计算这两个日子之间的天数;给定某个日期,返回它在一周中属于第几天;给定某年某月,以字符数组的形式产生该月的日历。

解答:这道题其实不难,关键点在于闰年判断以及某年某月的天数判断。麻烦的地方就是日历输出,要注意格式。

/***********************************************************/
// 程序目的:万年历查询
// 日期:    2014-09-02 
// 作者:    spencer_chong
// 邮箱:    zhuangxb91@qq.com
/***********************************************************/
#include <iostream> 
using namespace std; 


typedef struct Date
{
	int year;
	int month;
	int day;
}Date;

/******************************************************
闰年
①、普通年能整除4且不能整除100的为闰年。(如2004年就是闰年,1900年不是闰年)
②、世纪年能整除400的是闰年。(如2000年是闰年,1900年不是闰年)
*******************************************************/
bool checkYear(int year)
{
	return (year%400==0||(year%4==0&&year%100!=0));
}
/******************************************************
判断该月有多少天
*******************************************************/
int checkMonth(int year,int month)
{
	if(month == 1||month == 3||month == 5||month == 7||month == 8||month == 10||month == 12)
	{
		return 31;
	}
	else if(month == 2)
	{
		if(checkYear(year))
			return 29;
		else return 28;
	}
	else return 30;
}
/******************************************************
计算天数差
*******************************************************/
int dataSub(Date date1,Date date2)
{
	int index = date1.year;
	int numLeap = 0;
	int subDay = 0;
	while(index<=date2.year)
	{
		if(checkYear(index))
			numLeap++;
		index++;
	}
	subDay = 365*(date2.year-date1.year+1)+numLeap;

	index = date1.month-1;
	while(index>0)
	{
		subDay = subDay-checkMonth(date1.year,index);
		index--;
	}

	index = date2.month;
	while(index<13)
	{
		subDay = subDay-checkMonth(date2.year,index);
		index++;
	}
	return subDay+date2.day-date1.day;
	
}
/******************************************************
计算星期几
*******************************************************/
int weekCompute(Date date)
{
	Date date1;
	date1.year = 1900;
	date1.month = 1;
	date1.day = 1;
	int subDay = dataSub(date1,date);
	return	(subDay)%7+1;
}
void display(Date date)
{
	cout<<date.year<<"年"<<date.month<<"月   日历如下:"<<endl;
	cout<<"日  一  二  三  四  五  六 "<<endl;
	int week = weekCompute(date);
	int dayNum = checkMonth(date.year,date.month);
	if (week==7)week=0;
	
	int i=0,j=0;
	
	while(i!=week)
	{	
		cout<<"    ";
		i++;
		j++;
	}
	while(i<=6)
	{
		cout<<date.day<<"   ";
		date.day++;
		i++;
		j++;
	}
	while(date.day<=dayNum)
	{
		if(j%7==0)
		cout<<endl;
		
		if(date.day<10)
		cout<<date.day<<"   ";
		else
			cout<<date.day<<"  ";
		date.day++;
		j++;

	}
	cout<<endl;


}

int main() 
{ 
	int choice=0;
	int week;
	cout<<"请输入功能:【1】天数差查询 【2】星期几查询 【3】 指定月日历打印"<<endl;
    cin>>choice;
	int subDay;
	Date date1;
	Date date2;
	switch (choice)
	{
		case 1:
					cout<<"请输入两个日期:"<<endl;
					cin>>date1.year>>date1.month>>date1.day;
					cin>>date2.year>>date2.month>>date2.day;
					subDay = dataSub(date1,date2);
					cout<<subDay;
					break;
	           
		case 2:
					cout<<"请输入一个日期:"<<endl;
					cin>>date2.year>>date2.month>>date2.day;
					week = weekCompute(date2);
					cout<<week<<endl;
					break;
			   
		case 3:
					cout<<"请输入年份和月份:"<<endl;
					cin>>date1.year>>date1.month;
					date1.day = 1;
					display(date1);
					break;
			   
		default:    break;
	}
    return 0; 
} 
请输入功能:【1】天数差查询 【2】星期几查询 【3】 指定月日历打印
1
请输入两个日期:
2008 8 8
2014 9 2
2216
请按任意键继续. . .
请输入功能:【1】天数差查询 【2】星期几查询 【3】 指定月日历打印
2
请输入一个日期:
2014 9 2
2
请输入功能:【1】天数差查询 【2】星期几查询 【3】 指定月日历打印
3
请输入年份和月份:
2014 9
2014年9月   日历如下:
日  一  二  三  四  五  六
    1   2   3   4   5   6
7   8   9   10  11  12  13
14  15  16  17  18  19  20
21  22  23  24  25  26  27
28  29  30

第五题

问题:本问题将处理一小部分用连字符连接的英语单词方面的问题。下面的规则列表描述了一些以字母c结尾的单词的有效连接符连接:"et-ic", "al-is-tic", "s-tic", "p-tic", "-lyt-ic", "ot-ic", "an-tic","n-tic", "c-tic", "at-ic", "h-nic", "n-ic", "m-ic", "l-lic", "b-lic", "-clic", "l-ic","h-ic","f-ic",d-ic",-bic",a-ic",-mac","i-ac"。应用该规则进行,给定一个单词,返回后缀连字符连接。

解答:问题待解。有简单粗暴的方法,就是比较。想到好的方法再来更新。

第六题

问题:请构造一个“表单字母生成器”,要求改字母生成器可将数据库中的每一条记录都合成到一个定制的文档(这就是通常被称为“邮件合并”的特性)。请设计小型的模式和输入文件,测试一下程序的正确性。

解答:主要就是对标识符${}的解析。

/***********************************************************/
// 程序目的:表单生成器
// 日期:    2014-09-03 
// 作者:    spencer_chong
// 邮箱:    zhuangxb91@qq.com
/***********************************************************/
// ProgramPearl3_5.cpp : Defines the entry point for the console application.
//
#include <iostream>
#include <fstream>
#include <string>
#include <map>
using namespace std;

void GenerateList(char *outputFile, char *intputFile, map<string, string>& dict) 
{
ofstream output(outputFile);
ifstream intput(intputFile);

string line;
/****************************************************************************
输入文件逐行处理,也可以不这样做,只是为了写入文本方便而已。
(1)所有的查找函数都返回一个size_type类型,这个返回值一般都是所找到字符串的位置,
如果没有找到,则返回string::npos 
(2)所有和string::npos的比较一定要用string::size_type来使用
不要直接使用int 或者unsigned int等类型。
(3)string 类将 npos 定义为保证大于任何有效下标的值。
***************************************************************************/
while (getline(intput, line, '\n'))
{
	int beginPos =0;
	//从beginPos(初始化为0)开始查找 ${
	string::size_type pos = line.find("${", beginPos);

	while (pos!=string::npos ) 
	{
		beginPos = pos;
		//从pos(${开始位置)开始查找 }
		string::size_type endPos = line.find("}", pos); 
		//提取${ }中间则字符串,例如${1}则提取1,其实就是map的key
		string t = line.substr(pos +2, endPos - pos -2);
		//在map中查找value
		map<string, string>::iterator iter = dict.find(t);
		//如果这不是最后一个条目
		//iterator->first 关键字(key)
        //iterator->second 存储的数据(value)
		if (dict.end() != iter) 
		{
			line.replace(pos, endPos-beginPos+1, iter->second);
			beginPos += iter->second.length();
		}
		else
		{
			beginPos = endPos +1;
		}
		//更新搜索起始位置
		pos = line.find("${", beginPos);
	}
	output << line <<"\n\r";
}
	intput.close();
	output.close();
}

int main()
{
	map<string, string> m;
	m.insert(pair<string, string>("1","2014年"));
	m.insert(pair<string, string>("2","9月"));
	m.insert(pair<string, string>("3","3日"));
	m.insert(pair<string, string>("4","晴朗"));
	GenerateList("b.txt","a.txt",m);
	return 0;
}
文件a.txt内容
今天是,${1},${2},${3},
天气${4}
输出文本b.txt内容
今天是,2014年,9月,3日,
天气晴朗


第七题

问题:一般的词典都允许人们查阅单词的定义,问题2.1描述了一种允许人们查阅单词变位词的词典。请设计查阅单词正确拼写以及查阅单侧押韵的词典。讨论一下查阅一个整数序列(比如1、1、2、3、5、8、13、21、...),化学结构或者歌曲韵律结构的词典。

解答:略。重点在于提取标识符以及查找上。

第八题

问题:七段装置提供了一种廉价的十进制数字显示法。请编写一个程序,用五个数字显示一个16位的正整数。输出结构是一个具有5个字节的数组,当且仅当数字j的第i段打开时,字节j中的位i才是1.

解答:这里提供横向和纵向显示两种方法。

/***********************************************************/
// 程序目的:数码管显示(横向)
// 日期:    2014-09-03 
// 作者:    spencer_chong
// 邮箱:    zhuangxb91@qq.com
/***********************************************************/
// ProgramPearl3_5.cpp : Defines the entry point for the console application.
//
#include <iostream>
#include <math.h>
#include <string>
using namespace std;
//字符模板,从上往下依次为为数字0-9
bool table[][7]={{1,1,1,0,1,1,1},
		         {0,0,1,0,0,1,0},
	             {1,0,1,1,1,0,1},
	             {1,0,1,1,0,1,1},
				 {0,1,1,1,0,1,0},
				 {1,1,0,1,0,1,1},
				 {1,1,0,1,1,1,1},
				 {1,0,1,0,0,1,0},
				 {1,1,1,1,1,1,1},
				 {1,1,1,1,0,1,1}};
//辅助显示用的,总共输出五行,记录每一行每一位的状态
int DiplayTable [5][5]={0};

void Display(int input)
{


	int figure[5]={0};
	int f;
	int i,k,j;
	//依次取出五位数
	for(k = 0;k<5;k++)
	{
		int p = int(pow(double(10),double(4-k)));
		figure[k] = input/p;
		input -= figure[k]*p;
	}
	//依次求取每一行每一位的状态,1 3 5行必定为横向,标记为4,2和4行各有三种情况,分别标记为1 2 3
	for(i = 0;i<5;i++)
	{
		f=figure[i];
		if(table[f][0])
			DiplayTable[i][0] = 4;

		if(table[f][1]&&!table[f][2])
			DiplayTable[i][1] = 1;
		if(!table[f][1]&&table[f][2])
			DiplayTable[i][1] = 2;
		if(table[f][1]&&table[f][2])
			DiplayTable[i][1] = 3;

		if(table[f][3])
			DiplayTable[i][2] = 4;

		if(table[f][4]&&!table[f][5])
			DiplayTable[i][3] = 1;
		if(!table[f][4]&&table[f][5])
			DiplayTable[i][3] = 2;
		if(table[f][4]&&table[f][5])
			DiplayTable[i][3] = 3;
		if(table[f][6])
			DiplayTable[i][4] = 4;

	}
	//按显示模板输出
	for (i=0;i<5;i++)
	{
		for(j=0;j<5;j++)
		{
			switch(DiplayTable[j][i])
			{
			case 0:cout<<"    ";break;
			case 1:cout<<"|   ";break;
			case 2:cout<<"   |";break;
			case 3:cout<<"|  |";break;
			case 4:cout<<" -- ";break;
			}
			cout<<"      ";
		}
		cout<<endl;
	}
	

}

int main()
{
	int i;
	cin>>i;

	Display(i);
	return 0;
}
12345
           --        --                  --
   |         |         |      |  |      |
           --        --        --        --
   |      |            |         |         |
           --        --                  --
#include <iostream>
#include <memory>
using namespace std;

void  showNumber(int i)
{
	int j=i;
	switch(j)
	{
		case 0:printf(" --\n");break;
		case 1:printf("|");break;
		case 2:printf("  |\n");break;
		case 3:printf(" --\n");break;
		case 4:printf("|");break;
		case 5:printf("  |\n");break;
		case 6:printf(" --\n");break;
		default :break; 
	};
}
void  showNullNumber(int i)
{
	switch(i)
	{
		case 0:printf("\n");break;
		case 1:printf(" ");break;
		case 2:printf("   \n");break;
		case 3:printf("");break;
		case 4:printf(" ");break;
		case 5:printf("   \n");break;
		case 6:printf("\n");break;
		default :break; 
	};
}

void GraphFigure(int i)
{
	int show[7];
	int show0[]={1,1,1,0,1,1,1};
	int show1[]={0,1,0,0,1,0,0};
	int show2[]={1,0,1,1,1,0,1};
	int show3[]={1,0,1,1,0,1,1};
	int show4[]={0,1,1,1,0,1,0};
	int show5[]={1,1,0,1,0,1,1};
	int show6[]={1,1,0,1,1,1,1};
	int show7[]={1,0,1,0,0,1,0};
	int show8[]={1,1,1,1,1,1,1};
	int show9[]={1,1,1,1,0,1,1};
	
	
	switch(i)
	{
		case 0:memcpy(show,show0,sizeof(show));break;
		case 1:memcpy(show,show1,sizeof(show));break;
		case 2:memcpy(show,show2,sizeof(show));break;
		case 3:memcpy(show,show3,sizeof(show));break;
		case 4:memcpy(show,show4,sizeof(show));break;
		case 5:memcpy(show,show5,sizeof(show));break;
		case 6:memcpy(show,show6,sizeof(show));break;
		case 7:memcpy(show,show7,sizeof(show));break;
		case 8:memcpy(show,show8,sizeof(show));break;
		case 9:memcpy(show,show9,sizeof(show));break;
		default :break; 
	};
	for(int i=0;i<7;++i)
	{
		if(1 == show[i])
			showNumber(i);
		else
			showNullNumber(i);
	}

}
int main()
{
   for(int i=0;i<10;++i)
   {	
       GraphFigure(i);
       cout<<"\n\n";
   	
   }
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值