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

第一题

问题:有一段编程代码给出了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;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第一部分 基础 第1章 开篇 3 1.1 一次友好的对话 3 1.2 准确的问题描述 4 1.3 程序设计 4 1.4 实现概要 5 1.5 原理 6 1.6 习题 7 1.7 深入阅读 9 第2章 啊哈! 算法 11 2.1 三个问题 11 2.2 无处不在的二分搜索 12 2.3 基本操作的威力 13 2.4 排序 15 2.5 原理 16 2.6 习题 17 2.7 深入阅读 18 2.8 变位词程序的实现(边栏) 18 第3章 数据决定程序结构 21 3.1 一个调查程序 21 3.2 格式信函编程 23 3.3 一组示例 25 3.4 结构化数据 26 3.5 用于特殊数据的强大工具 27 3.6 原理 28 3.7 习题 29 3.8 深入阅读 30 第4章 编写正确的程序 33 4.1 二分搜索的挑战 33 4.2 编写程序 34 4.3 理解程序 36 4.4 原理 38 4.5 程序验证的角色 39 4.6 习题 40 4.7 深入阅读 42 第5章 编程小事 43 5.1 从伪代码到C程序 43 5.2 测试工具 44 5.3 断言的艺术 46 5.4 自动测试 48 5.5 计时 49 5.6 完整的程序 50 5.7 原理 51 5.8 习题 51 5.9 深入阅读 52 5.10 调试(边栏) 53 第二部分 性能 第6章 程序性能分析 57 6.1 实例研究 57 6.2 设计层面 59 6.3 原理 60 6.4 习题 61 6.5 深入阅读 61 第7章 粗略估算 63 7.1 基本技巧 64 7.2 性能估计 66 7.3 安全系数 68 7.4 Little定律 69 7.5 原理 70 7.6 习题 70 7.7 深入阅读 71 7.8 日常生活中的速算(边栏) 72 第8章 算法设计技术 73 8.1 问题及简单算法 73 8.2 两个平方算法 74 8.3 分治算法 75 8.4 扫描算法 77 8.5 实际运行时间 77 8.6 原理 79 8.7 习题 80 8.8 深入阅读 81 第9章 代码调优 83 9.1 典型的故事 83 9.2 急救方案集锦 84 9.3 大手术——二分搜索 88 9.4 原理 91 9.5 习题 92 9.6 深入阅读 94 第10章 节省空间 95 10.1 关键在于简单 95 10.2 示例问题 96 10.3 数据空间技术 99 10.4 代码空间技术 101 10.5 原理 103 10.6 习题 104 10.7 深入阅读 105 10.8 巨大的节省(边栏) 105 第三部分 应用 第11章 排序 109 11.1 插入排序 109 11.2 一种简单的快速排序 110 11.3 更好的几种快速排序 113 11.4 原理 115 11.5 习题 116 11.6 深入阅读 117 第12章 取样问题 119 12.1 问题 119 12.2 一种解决方案 120 12.3 设计空间 121 12.4 原理 123 12.5 习题 124 12.6 深入阅读 125 第13章 搜索 127 13.1 接口 127 13.2 线性结构 129 13.3 二分搜索树 132 13.4 用于整数的结构 134 13.5 原理 135 13.6 习题 136 13.7 深入阅读 137 13.8 一个实际搜索问题(边栏) 137 第14章 堆 141 14.1 数据结构 141 14.2 两个关键函数 143 14.3 优先级队列 145 14.4 一种排序算法 148 14.5 原理 150 14.6 习题 150 14.7 深入阅读 152 第15章 字符串 153 15.1 单词 153 15.2 短语 156 15.3 生成文本 158 15.4 原理 163 15.5 习题 163 15.6 深入阅读 164 第1版跋 165 第2版跋 167 附录A 算法分类 169 附录B 估算测试 173 附录C 时空开销模型 175 附录D 代码调优法则 181 附录E 用于搜索的C++类 187 部分习题提示 191 部分习题答案 195 索引 221

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值