VS工具制作控制台日历中算法的启发

   前些天的学习任务是利用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());
                }

该算法思路清晰明了,方便分析问题。其实,在后续学习了递归之后,对于前一个算法,可以利用递归的方式不断重复使用函数。但尚不清楚在运算速度和占用内存的比较上的优劣。出于在解决该类问题钟不同思路带来的不同算法的思考上,初学者们应当沉下心来,仔细分析问题,尝试思考不同的算法,取其优者。一方面开拓思路,一方面也是一个成熟的程序开发者不得不考虑的问题

猜你喜欢

转载自www.cnblogs.com/PoetSAW/p/9195420.html
今日推荐