以下题目摘自人民邮电出版社《数据结构——Python语言描述》82页:
综合实验3 每日快递
实验目的:深入理解循环单链表的存储结构,熟练掌握循环单链表的基本操作。
实验背景:瑶湖快递的快递员张小明每日负责 N 市高新技术开发区中 10 个居民小区的快递派送任务,张小明会在每天上午 9 点和下午 2 点分别进行两次派送,图 2-38 所示(笔者注:图找不到,就不贴了)为张小明每日的派送路线。快递公司规定,在派送过程中,快递员还应该接收小区内已预定寄出的快递,若某小区需要派送的快递个数和接收的快递个数均为零,快递员则不需要前往该小区,而是直接前往下一小区进行派送。每日派送结束后,公司对每位快递员去过的小区数目及收寄快递的数量进行清点。假设表 2-19 所示为张小明今日的工作记录,请借助于循环单链表来实现公司对张小明当日派送任务的清点。
表 2-19 张小明今日工作记录
实验内容:创建文件 ex030502_03.py,并在其中编写快递派送清算程序,具体如下。
(1)创建循环单链表 A ,并将小区编号作为参数创建相应结点,并依次链入循环单链表 A 中。
(2)通过扫描 A ,记录下快递员走过的小区个数,并将派送快递的总个数、接收快递的总个数存入当前结点的数据域中。
(3)输出快递员走过的小区个数、派送快递的总个数。
实验提示:
(1)每个结点应有两个数据域,分别用于存放收件数和派件数。
(2)可借助数组或手动输入来更新每个小区派送和接收快递的个数。
(3)可借助数组或列表来完成计数操作。
看完题目,笔者就觉得这题出得不太好,因为这样的题目犯不上使用循环单链表。再细读一遍实验提示之后,觉得这条题目确实是存在令人费解的地方的。特别是这句:
可借助数组或列表来完成计数操作
这句完全是不需要做的,直接使用三个变量即可。
还有,题目说
将小区编号作为参数创建相应结点
但其实我们可以在创建的同时存值进去,不用这么麻烦。
因此,笔者打算先贴一份不完全按照题目要求的代码:
class Node:
def __init__(self,send=None,receive=None,next=None):
self.send=send
self.receive=receive
self.next=next
class CircularSingleLinkedList:
def __init__(self):
self.head=Node()
self.head.next=self.head
def creat(self,lst):
cur=self.head
for i in lst:
cur.next=Node(i[0],i[1],self.head)
cur=cur.next
def update(self,lst):
cur=self.head.next
for i in lst:
cur.send,cur.receive=i[0],i[1]
cur=cur.next
def count(self):
cur=self.head.next
cnt,sumsend,sumreceive=0,0,0
while cur!=self.head:
if cur.send!=0 or cur.receive!=0:
cnt+=1
sumsend+=cur.send
sumreceive+=cur.receive
cur=cur.next
return [cnt,sumsend,sumreceive]
if __name__ == '__main__':
a=CircularSingleLinkedList()
lst1=[[8,0],[5,2],[6,4],[0,0],[8,0],[0,0],[2,1],[2,0],[1,1],[3,1]]
lst2=[[2,1],[1,3],[2,5],[4,0],[7,0],[9,0],[1,0],[1,2],[1,1],[0,0]]
a.creat(lst1)
print(a.count())
a.update(lst2)
print(a.count())
##输出:
##[8, 35, 9]
##[9, 28, 12]
可以看到,这里的代码没有用到循环单链表的特性,只不过把它当单链表使用了。然后,像上面所讲的,代码是使用三个变量来统计数据的,没有用到数组,也没有先建好再存值。
但是,这毕竟是在做题目,因此笔者不得不贴出这一份尽量符合题目要求的代码:
class Node:
def __init__(self,send=None,receive=None,next=None):
self.send=send
self.receive=receive
self.next=next
class CircularSingleLinkedList:
def __init__(self):
self.head=Node()
self.head.next=self.head
def creat(self,n):
cur=self.head
for i in range(n):
cur.next=Node(None,None,self.head)
cur=cur.next
def update(self,lst):
cur=self.head.next
for i in lst:
cur.send,cur.receive=i[0],i[1]
cur=cur.next
def count(self):
cur=self.head.next
cnt=0
cntlst=[]
while cur!=self.head:
if cur.send!=0 or cur.receive!=0:
cnt+=1
cntlst.append([cur.send,cur.receive])
cur=cur.next
return [cnt,sum(i[0] for i in cntlst),sum(i[1] for i in cntlst)]
if __name__ == '__main__':
a=CircularSingleLinkedList()
n=10
lst1=[[8,0],[5,2],[6,4],[0,0],[8,0],[0,0],[2,1],[2,0],[1,1],[3,1]]
lst2=[[2,1],[1,3],[2,5],[4,0],[7,0],[9,0],[1,0],[1,2],[1,1],[0,0]]
a.creat(n)
a.update(lst1)
print(a.count())
a.update(lst2)
print(a.count())
##输出:
##[8, 35, 9]
##[9, 28, 12]
这份代码修改了creat
方法和count
方法,主程序中也做了相应改变。可以看到,如果完全遵照题目的意思来的话,代码是很不优美的,而且循环的性质依然没有用上。
其实,为了使用到循环的特性,我们可以写一份更丑的代码,即,使用三遍循环,第一遍建立链表,同时存上午的值;第二遍遍历链表,记录上午数据,并更新结点为下午的数据;第三遍再遍历一次链表,记录下午数据。由于这么写代码实在太过冗长,且耦合度极高,这里就不贴出了。