前些天的学习任务是利用VS工具编码实现控制台显示任意年份和月份对应的日历。因为关系到年份和月份,很容易考虑到润年的情况,故功能需求中对于润年的判断及相对应月份天数的判断利用多个for循环和if判断均可轻易实现。但作为该任务最难也是最重要的一点是,当月日历会承接上月的星期而显示一定数量的空白,如图所示:
这个功能的实现,需要找到每个月空白的规律。在没有提示的情况下,萨摩观察了多个月的规律,得到这样的关系:设一只1900年1月1号前为1个空白,则该月末有5*7-1-当月天数即35-1-31=3个空白,则2月初就有7-3=4个空白,以此类推的到一个关系式,设当月出空白书为i,则月末空白数为35-i-当月天数,而第二个月初i下月=7-上月末天数即把i下月=i上月+上月天数-28,且当i=7的时候,实际上没有空白即if(i==7){i=0};综上,可得到判断当月日历前有多少空白的算法编码:
for(int i=1,j=1900,day,month=1;j<=year&&month<=12;j++,month++) { if(i==7) { i=0; continue; } else if(month==2) { if(j%4==0&&j%100!=0||j%400==0) { day=29; } else { day=28; } else if(month<=7&&month%2!=0||month>7&&month%2==0) { day=31; } else { day=30; } i=i+day-29 } }
基本思路就是利用之前得到的关系式,通过循环,依次算出从1900年1月1号到输入年份月份后定位的日期退出循环输出i的值。在未学习函数递归之前,可想而知这种通过不对循环的方式进行类推的算法及其冗长和业余,而且代码的正确性尚不能保证。之后,老师给予了算法的新思路,即无论何年,在某月日历前的空白数即为当月1号的星期数(当然如果日历是从周一开始算,即为当月1号星期数-1),这样,只要知道用户输入的年份和月份下,当月1月1号是星期几,就能轻松知道当月日历的空白数,从而将问题转化成寻找星期数。要知道某年某月1月1号的星期,可以在一只1900年1月1号为星期一的条件下,分别计算从1900年到用户输入年份经过了多少天数和用户输入年份当年1月1号到用户输入月份经过了多少天数,求得总天数后,求余7即可知道当月1月1号是星期几。至于对于润平年和大小月的判断,自不在话下。即:
List<string> day = new List<string>(); int daysPassedOfYears = 0; for (int i = 1900; i < year; i++) { if (i % 400 == 0 || i % 4 == 0 && i % 100 != 0) { daysPassedOfYears += 366; } else { daysPassedOfYears += 365; } } int daysPassedOfMonth = 0; for (int i = 1; i < month; i++) { if (i == 2) { if (year % 400 == 0 || year % 4 == 0 && year % 100 != 0) { daysPassedOfMonth += 29; } else { daysPassedOfMonth += 28; } } else if (i < 7 && i % 2 != 0 || i > 7 && i % 2 == 0) { daysPassedOfMonth += 31; } else { daysPassedOfMonth += 30; } } int daysPassed = daysPassedOfMonth + daysPassedOfYears; int dayOfWeek = daysPassed % 7 + 1; int blanks = dayOfWeek; if (blanks == 7) { blanks = 0; } for (int i = 0; i < blanks; i++) { day.Add(" "); } #endregion #region 获取当月所有的天数 int j; if(month==2) { if (year % 400 == 0 || year % 4 == 0 && year % 100 != 0) { j = 29; } else { j = 28; } } else if (month <= 7 && month % 2 != 0 || month > 7 && month % 2 == 0 && month != 2) { j = 31; } else { j = 30; } for (int i = 1; i <= j; i++) { day.Add(i.ToString()); }
该算法思路清晰明了,方便分析问题。其实,在后续学习了递归之后,对于前一个算法,可以利用递归的方式不断重复使用函数。但尚不清楚在运算速度和占用内存的比较上的优劣。出于在解决该类问题钟不同思路带来的不同算法的思考上,初学者们应当沉下心来,仔细分析问题,尝试思考不同的算法,取其优者。一方面开拓思路,一方面也是一个成熟的程序开发者不得不考虑的问题
原文地址:https://www.cnblogs.com/PoetSAW/p/9195420.html