编程实现万年历,要求:
可根据用户输入或系统日期进行初始化,如果用户无输入则显示系统日期所在月份的月历,并突出显示当前日期;
可根据用户输入的日期查询,并显示查询结果所在月份的月历,突出显示当前日期,并提示是否闰年
对任何不合法输入数据,拒绝查询并进行提示。
思路分析可将思考、编程划分为以下几个模块:
如何通过已有日期和星期推算要求的日期的星期?
如何整齐地输出月历?
如何获取系统时间?
在有余力的前提下,如何美化界面?
下面对上面的几个问题给出粗略的概述。
具体实现和技巧性地东西参考后文代码。
问题1日期推算众所周知,需要推算日期的模拟题都是*瘤题
日期推算的算法有很多,这里只给出我的思路:
推出差了多少天。
用数学公式推出星期。
这条公式是(w+d)mod7(w+d)mod7,d表示差的天数,w表示原本是星期几。
我采用的是标准的0表示Sun.而6表示Sat.的方法。
time.h自带的tm_wday就是用这种方式表示的。
需要注意的是C与C++对负数取模的特(sha)殊(bi)性,所以为了求出正确的结果,我们要采用一点小技巧。
if(w1+d0)w2=(w1+d)+(-w1-d)/7*7+7;
似乎也可以在推出天数后乘上减一下然后扔给localtime()去推星期。
但是你连天数都推出来了,直接算不香吗。而且既然是万年历,秒数太大爆了怎么办
接下来让我们考虑如何推算差了多少天。
我为了方便计算,所有的推算都以年1月1日星期三为基准。
由一个基准来推的化可以省去很多麻烦。
首先,第一种方法是暴力模拟。一年一年地推、一月一月地推、一天一天地推。
我在代码中注释掉的就是暴力模拟法。
这个没什么好讲的,闰年就差天,否则差天。
年推到了就推月,实现把每个月份的天数打个表,别忘了特判二月就行。
你也可以不像我那样偷懒一个一个月推,使用前缀和数组+闰年特判也行。但是每次查询最多就推12个月,一个月一个月推也差不了多少。
这点时间肉眼是看不出来的。所以随便吧。
天数就没什么好说的,自己随便想两个同年同月的日期看看差几天,很快就能看出是直接拿日期相减了。
其实,我们不难发现,年份可以不用一年一年模拟,可以用数学公式算。
现在我们要算A年1月1日到B年1月1日经过了几个闰年。
以AB为例
直接拿(B-A)/4来算闰年个数这种玄学的事情我是不会干的。我希望求出的闰年个数是绝对准确的。
因此可以这样来:
我们知道x/4可以表示小于等于x的正整数中4的倍数的个数。
我们需要求经过的闰年的个数,只需要知道区间[A,B-1]中4、、的倍数的个数就行了。
(因为我考虑的是1月1日,如果考虑12月31日的话,应该变为[A+1,B])
根据容斥原理,记4、、的倍数的个数分别为c1,c2,c3c1,c2,c3
我们有:n=c1?c2+c3n=c1?c2+c3
根据前缀和的思想,我们有:
c1=(B?1)/4?(A?1)/4c1=(B?1)/4?(A?1)/4
应该不会有人看不懂前缀和吧,不过我还是解释一下吧。
因为A是包含在区间里面的,我们要求[A,B-1]的区间权值,自然不能把A删出去,所以要用A-1。
其它几项同理。
于是我们求出了闰年的个数,于是d=(B?A)+n×1d=(B?A)+n×1
至于AB的情形,同理,只需要把区间改为[B,A-1]。
然后根据前缀和,你会发现式子是一样的,只是正负号变了而已,所以没有分类讨论的必要。
这样就解决了最关键的问题,剩下的只需要动用知识和耐心去模拟就好了。
问题2月历的格式这个随便百度一下万年历或者点一下右下角的时间模仿一下它的格式就行了。这里介绍几个技巧。
分行printf(这个好像谁都会)
对齐
利用%-*d可以靠左对齐,%*d则是靠右对齐。
总之计算好需要的字符长度然后分配即可。看着不行多试几次。
利用字符数组减少工作量
需要注意的是,二维数组的字符串长度必须声明。因为只有知道了长度才可以分配内存。二维数组不止要分配第一个字符串的内存,还要同时按间隔分配余下的内存,不规定长度的话它不知道要在哪里放第二个。
问题3time.h的简单用法需要注意的是tm_year返回的是差值,且tm_mon是从0开始的
直接放代码和注释。
问题4美化基于我对cmd界面的认识,我认为改动颜色可以使他更好看!
效果图源码分享:那么今天的文章就分享到这里了,希望对大家能够有帮助呀!
另外如果你想更好的提升你的编程能力,学好C语言C++编程!弯道超车,快人一步!
C语言C++编程学习交流圈子,QQ群
分享(源码、项目实战视频、项目笔记,基础入门教程)
欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!
编程学习书籍分享:
编程学习视频分享:
预览时标签不可点收录于话题#个上一篇下一篇