python数据结构学习笔记-2016-10-05-02-抽象数据类型(二)

        1.2 日期抽象数据类型

        本节以日期为例,阐述抽象数据类型。

        1.2.1 定义ADT

  • Date(month, day, year):根据给定的公历日期,创建日期实例,公元前的年份以负数表示;
  • day():返回公历日期的某日;
  • month():返回公历日期的某月(数字);
  • year():返回公历日期的某年;
  • monthName():返回公历日期的某月的月份名;
  • dayOfWeek():返回星期几(0-6);
  • numDays(otherDay):与otherDay相差的天数(正整数);
  • isLeapYear():判断是否是闰年;
  • advanceBy(days):返回当前日期增加days天的日期(days可为负数);
  • comparable(otherDate):比较当前日期与otherDate的逻辑关系,即前后,可使用逻辑符号<,>,<=,>=,==,!=;
  • toString():以mm/dd/yyyy的字符串形式返回公历日期。  
        使用python中的类来实现ADT,则上述为类中的属性和方法。

        1.2.2 使用ADT
        以下的例子说明,我们可以不用去可以关注ADT的实现,而直接使用ADT来达到我们的目的。即便当ADT的实现方式改变时,也无需更新代码。
#-*-coding: utf-8-*-

from date import Date

# 获取用户输入的出生日期
def promptAndExtracDate():
    print "Enter a birth date."
    month = int(raw_input("month (0 to quit): "))
    if month == 0:
        return None
    else:
        day = int(raw_input("day: "))
        year = int(raw_input("year: "))
        return Date(month, day, year)

def main():
    bornBefore = Date(6, 1, 1988) 
    
    date = promptAndExtracDate()
    while date is not None:
        if date <= bornBefore:
            print "Is at least 21 years of age:", date
        date = promptAndExtracDate()

if __name__ == "__main__":
    main()

        1.2.3 前置条件和后置条件
        前置条件(preconditions):在进行相应操作前的ADT实例和输入的条件或状态。(输入是什么鬼?)
        后置条件(postconditions):在进行相应操作后的ADT实例的结果或结束状态。
        前置条件为真是操作顺利进行的前提,比如说python中pop(i),索引i必须位于列表长度范围之内,这就是前置条件。显然如果索引i不在列表索引范围之内,pop(i)就会引发异常。
        通常来说,所有操作都必须至少有一个前置条件,那就是ADT实例必须初始化。在OOP中,实例创建就伴随着初始化的过程。有些操作还有其他的前置条件,比如说前述的pop(i)。
        有些操作可能没有后置条件,比如说访问实例,可能仅会返回某个值,而不改变实例的状态。
        异常(exception)
        在整本书中,使用断言异常来表示当前置条件不成立时,引发的异常。这样做可使我们不必考虑具体引发哪种异常或者说是新建异常。

        1.2.4 实现ADT
        日期表示有两。,一种是以元组形式(month, day, year),这种表示一目了然,但是不便于计算两个日期之间相差的天数。另外一种是儒略日表示法,具体百度或google,这种表示方法利于计算两个日期之间相差的天数,但是看着很别扭。在以下实现日期ADT的过程中,我们采取后者,因为后者便于储存。(另外猜测内存占用小),但也提供两者表示法的转换,只是采用后者来储存。
#-*-coding: utf-8-*-

# 通过儒略日格式实现公历日期

class Date(object):
    # 创建公历日期实例对象
    def __init__(self, month, day, year):
        self._julianDay = 0
        assert self._isValidGregorian(month, day, year), "Invalid Gregorian date." # 判断输入日期是否晚于公元前4713年11月24日(公历表示)
    
        tmp = 0
        if month < 3:
            tmp = -1
        self._julianDay = day - 32075 + (1461 * (year + 4800 + tmp) / 4) + (367 * (month - 2 - tmp * 12) / 12) - (3 * ((year + 4900 + tmp) / 100) / 4)

    # 提取公历日期的组件
    def month(self):
        return (self._toGregorian())[0] # 从(M, d, y)返回M

    def day(self):
        return (self._toGregorian())[1] # 从(m, D, y)返回D

    def year(self):
        return (self._toGregorian())[2] # 从(m, d, Y)返回Y

    # 返回星期几
    def dayOfWeek(self):
        month, day, year = self._toGregorian()
        if month < 3:
            month += 12
            year -= 1
        return ((13 * month + 3) / 5 + day + year + year / 4 - year / 100 + year / 400) % 7

    # 以通用日期格式返回日期
    def __str__(self):
        month, day, year = self._toGregorian()
        return "%02d/%02d/%04d" % (month, day, year)

    # 比较两个日期
    def __eq__(self, otherDate):
        return self._julianDay == otherDate._julianDay

    def __lt__(self, otherDate):
        return self._julianDay < otherDate._julianDay

    def __le__(self, otherDate):
        return self._julianDay <= otherDate._julianDay

    # 待补充
    # def isValidGregorian(month, day, year):
    # ......

    # 以元组形式返回公历日期
    def _toGregorian(self):
        A = self._julianDay + 68569
        B = 4 * A / 146097
        A = A - (146097 * B + 3) / 4
        year = 4000 * (A + 1) / 1461001
        A = A - (1461 * year / 4) + 31
        month = 80 * A / 2447
        day = A - (2447 * month / 80)
        A = month / 11
        month = month + 2 - (12 * A)
        year = 100 * (B - 49) + year + A
        return month, day, year


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值