趁着刚考完还没上小学期的课程,用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
欢迎有兴趣的小伙伴们提意见和指出不足之处~