HIT软件构造Lab3(python版)

趁着刚考完还没上小学期的课程,用python把lab3重写了一遍,没有写app和附加要求了

# MIT软件构造实验Lab3, 2021.07.11
"""
三种不同类型的时间段集合类
"""

from abc import ABCMeta
from abc import abstractmethod


class IntervalSet(metaclass = ABCMeta):
    """
    时间段集合抽象类
    """

    @abstractmethod
    def insert(self, i):
        """
        插入一个时间段
        :param i: 时间段
        :return: 无
        """

    @abstractmethod
    def labs(self):
        """
        :return: 时间段集合里所有的标签
        """

    @abstractmethod
    def remove(self, lab):
        """
        移出一个标签表示的所有时间段
        :param lab: 移除的标签
        :return: 是否移除成功
        """

    @abstractmethod
    def get_interval(self, lab):
        """
        :param lab: 标签
        :return: 这个标签所有的时间段组成的集合
        """


class Interval:
    """
    时间段类
    """

    def __init__(self, start, end, lab):
        self.__start = start
        self.__end = end
        self.__lab = lab
        self.checkRep()

    def checkRep(self):
        """
        检查RI不变性
        """
        assert self.__start > 0
        assert self.__end > self.__start
        assert self.__lab is not None

    def start(self):
        """
        :return: 开始时间
        """
        return self.__start

    def end(self):
        """
        :return: 结束时间
        """
        return self.__end

    def lab(self):
        """
        :return: 标签
        """
        return self.__lab

    def is_conflict(self, other):
        """
        :param other: 另一个时间段
        :return: 两个时间段是否存在冲突
        """
        return (self.start() < other.end()) & (self.end() > other.start())

    def is_link(self, other):
        """
        :return: 判断两个时间段是否不重合,并且可以无缝拼接在一起
        """
        return (self.start() == other.end()) | (self.end() == other.start())

    def __eq__(self, other):
        # 重写了该方法,Interval类对象变成了不可哈希
        return (self.start() == other.start()) & (self.end() == other.end()) & (self.lab() == (other.lab()))

    def __lt__(self, other):
        if self.start() != other.start():
            return self.start() <= other.start()
        else:
            return self.end() <= other.end()

    def __repr__(self):
        return "%s: [%d, %d)" % (self.__lab, self.__start, self.__end)


class CommonIntervalSet(IntervalSet):
    """
    限制性最小的时间段集合类,可以重叠,可以重复标签,可以有空白
    """

    def __init__(self):
        self.__ls = []

    def checkRep(self):
        """
        检查属性是否符合要求
        """
        for inter in self.__ls:
            inter.checkRep()

    def insert(self, inter):
        """
        插入一个时间段
        :param inter: 时间段
        :return: 是否插入成功
        """
        if inter.lab() in self.labs():
            # 如果有重复标签,需要进行同标签时间段合并
            for inter1 in self.__ls:
                if inter1.lab() == inter.lab():
                    # 如果两个标签没有重叠并且中间隔了一段距离
                    if inter1.is_conflict(inter) | inter1.is_link(inter):
                        inter2 = Interval(min(inter.start(), inter1.start()), max(inter.end(), inter1.end()),
                                          inter.lab())
                        self.__ls.remove(inter1)
                        self.__ls.append(inter2)
                        self.__ls.sort()
                        self.checkRep()
                        return True
        # 没有标签重复
        self.__ls.append(inter)
        self.__ls.sort()
        self.checkRep()
        return True

    def labs(self):
        """
        :return: 时间段集合里所有的标签
        """
        labs = set()
        for inter in self.__ls:
            labs.add(inter.lab())
        return labs

    def labs_for_time(self, time):
        """
        :param time: 时间点
        :return: 时间点对应的标签集合
        """
        labs = set()
        for inter in self.__ls:
            if (inter.start() <= time) & (inter.end() > time):
                labs.add(inter.lab())
        return labs

    def max_time(self):
        """
        :return: 最大时间
        """
        max_time = 0
        for inter in self.__ls:
            if max_time < inter.end():
                max_time = inter.end()
        return max_time

    def remove(self, lab):
        """
        移出一个标签表示的所有时间段
        :param lab: 移除的标签
        :return: 是否移除成功
        """
        is_remove = False
        n = len(self.__ls)
        index = 0
        while index < n:
            if self.__ls[index].lab() == lab:
                self.__ls.remove(self.__ls[index])
                n -= 1
                index -= 1
                is_remove = True
            index += 1
        self.checkRep()
        return is_remove

    def get_interval(self, lab):
        """
        :param lab: 标签
        :return: 这个标签所有的时间段组成的集合
        """
        interval_set = []
        for inter in self.__ls:
            if inter.lab() == lab:
                interval_set.append(inter)
        return tuple(interval_set)

    def get_list(self):
        """
        :return: 时间段列表
        """
        return list(self.__ls)

    def __repr__(self):
        s = "{"
        n = len(self.__ls)
        for index in range(n):
            s += str(self.__ls[index])
            if index < n - 1:
                s += ", "
        s += "}"
        return s


class MultiIntervalSet(CommonIntervalSet):
    """
    时间段集合,任意两个时间段不能有重叠,可以有重复标签
    """

    def __init__(self):
        super().__init__()

    def checkRep(self):
        """
        检查属性是否符合要求
        """
        ls = []
        super().checkRep()
        for inter in self.get_list():
            if ls.append(inter.lab()):
                # 检查有无重复标签
                assert False
            ls.append(inter)

    def insert(self, inter):
        """
        插入一个时间段
        :param inter: 插入的时间段
        :return: 是否插入成功
        """
        # 先判断有无不一样标签的时间段重合
        ls = self.get_list()
        for inter1 in ls:
            if inter1.is_conflict(inter) & (inter1.lab() != inter.lab()):
                raise ConflictException
        super().insert(inter)
        self.checkRep()
        return True

    def similarity(self, other):
        """
        两个Multi时间段集合对象的相似度
        :param other: 另一个Multi对象
        :return:
        """
        similarity = 0
        max_time = max(self.max_time(), other.max_time())
        for time in range(max_time):
            if self.labs_for_time(time) == other.labs_for_time(time):
                similarity += 1
        return similarity / max_time


class LinearIntervalSet(MultiIntervalSet):
    """
    限制性最大的时间段集合,不能有重复标签,重叠区域
    """

    def __init__(self):
        super().__init__()

    def checkRep(self):
        """
        检查属性是否符合要求
        """
        labs = set()
        ls = self.get_list()
        for inter in ls:
            if inter.lab() in labs:
                assert False
            labs.add(inter.lab())

    def insert(self, inter):
        """
        插入一个时间段
        :param inter: 要插入的时间段
        :return: 是否插入成功
        """
        # 先判断是否list中是否有与插入标签相同的标签
        # 若有,看两个标签是否有重叠区域,如果没有直接抛出异常
        ls = self.get_list()
        for inter1 in ls:
            if (inter.lab() == inter1.lab()) & (not inter.is_conflict(inter1)) & (not inter.is_link(inter1)):
                raise RepeatException
        super().insert(inter)
        self.checkRep()
        return True

    def get_interval(self, lab):
        """
        :param lab: 一个标签
        :return: 该标签表示的时间段(只有一个)
        """
        return super().get_interval(lab)[0]


class ConflictException(Exception):
    """
    时间段冲突异常
    """
    pass


class RepeatException(Exception):
    """
    标签重复异常
    """
    pass

欢迎有兴趣的小伙伴们提意见和指出不足之处~

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值