Python數據結構練習之每日快遞

以下題目摘自人民郵電出版社《數據結構——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方法,主程序中也做了相應改變。可以看到,如果完全遵照題目的意思來的話,代碼是很不優美的,而且循環的性質依然沒有用上。

其實,爲了使用到循環的特性,我們可以寫一份更醜的代碼,即,使用三遍循環,第一遍建立鏈表,同時存上午的值;第二遍遍歷鏈表,記錄上午數據,並更新結點爲下午的數據;第三遍再遍歷一次鏈表,記錄下午數據。由於這麼寫代碼實在太過冗長,且耦合度極高,這裏就不貼出了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章