# [資演] 5-Linked List (II): Singly linked list 上的操作 ###### tags: `資演` ## Linked list 的插入操作 對於一個非空的 linked list,我們的插入(insertion)可以有三種可能: 1. 在 head 之前插入,所插入節點成為新的 head ![](https://hackmd.io/_uploads/S1l_UxyhY.png) 2. 在中間插入,插入的節點成為中間的節點 ![](https://hackmd.io/_uploads/HkUYIgyhF.png) 3. 在 tail 之後插入,所插入節點成為新的 tail ![](https://hackmd.io/_uploads/HkcdLl13Y.png) 於是,插入操作的演算法流程如下: ![](https://hackmd.io/_uploads/SyHkixy2Y.png) 一個定義在`LinkedList`裡面的`insert`方法的程式碼如下:: ``` def insert(self, value, location): newNode = Node(value) if self.head is None: self.head = newNode self.tail = newNode else: if location == 0: newNode.next = self.head self.head = newNode elif location == -1: newNode.next = None self.tail.next = newNode self.tail = newNode else: tempNode = self.head index = 0 while index < location - 1: tempNode = tempNode.next index += 1 nextNode = tempNode.next tempNode.next = newNode newNode.next = nextNode ``` ## 巡訪 linked list Linked list的巡訪相當簡單,只要順著指標一個一個連下去就好了: ![](https://hackmd.io/_uploads/HJmQQW1nY.png) 其程式碼如下: ``` def traverse(self): if self.head is None: return "The linked list does not exist" else: node = self.head while node is not None: print(node.value) node = node.next ``` ## 在 linked list 裡面尋找一個元素 尋找一個元素的操作和巡訪相當類似,主要有以下兩點和巡訪不同: 1. 我們需要先輸入一個要尋找的目標值 2. 終止條件為找到那個值 ![](https://hackmd.io/_uploads/rJY-_RPnY.png) ``` def search(self, nodeValue): if self.head is None: return "The linked list does not exist" else: node = self.head while node is not None: if node.value == nodeValue: return node.value node = node.next return "The node does not exist in this linked list" ``` ## Linked list 的刪除操作 Linked list 的刪除操作,我們一樣可以分為三種情形來看: 1. 刪除第一個節點,即head 2. 刪除中間節點 3. 刪除最後一個節點,即tail ![](https://hackmd.io/_uploads/SJr_zfo3K.png) ![](https://hackmd.io/_uploads/HJCIspc3t.png) ``` def delete(self, location): if not self.head: return "The linked list does not exist" else: if location == 0: if self.head == self.tail: self.head = None self.tail = None else: self.head = self.head.next elif location == -1: if self.head == self.tail: self.head = None self.tail = None else: node = self.head while node: if node.next == self.tail: break node = node.next node.next = None self.tail = node else: tmp = self.head index = 0 while index < location-1: tmp = tmp.next index += 1 nextNode = tmp.next tmp.next = nextNode.next ``` ## 例題 * 找出位在 linked list 最中間的那個數 ![](https://hackmd.io/_uploads/H1CRyXn3F.png) 這是一個經典的題目,想想看在只能單向尋訪整個linked list、而且不能由index來呼叫的時候,你要怎麼找出最中間的那個節點呢? :::spoiler 解答 想像現在有一隻烏龜和一隻兔子在賽跑。兔子跑步的速度是一直維持在烏龜的速度的兩倍,當兔子跑到終點的時候,烏龜在哪裡? 答案是在中點。 運用這個概念,我們可以使用兩個指針來尋訪整個linked list,一個快指針一次跳兩格(`fast`),一個慢指針一次只跳一格(`slow`)。當快指針走到linked list的末端的時候,慢指針應該就會在我們希望得到的中間點上。 ``` class Solution: def middleNode(self, head): fast = head slow = head try: while fast: fast = fast.next.next slow = slow.next except: return slow return slow ``` ::: * 相加兩個整數 現在你手上有兩個非空的 linked list,他們分別代表兩個大於等於 0 的整數。每個 linked list 上的節點儲存一個位數,儲存順序和你閱讀那個整數的順序相反,例如 ![](https://hackmd.io/_uploads/r1zhDgnnt.png) 代表的是 $342+465=807$。 :::spoiler 解答 因為linked list上的數字順序已經是由低位數到高位數排列,你可以使用你平常心算加法時的邏輯來編寫這個程式。 ![](https://hackmd.io/_uploads/HkXQoennK.png) ``` # Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def addTwoNumbers(self, l1, l2): offset = 0 this1 = l1 this2 = l2 this_head = ListNode() this = this_head while this1 or this2 or int(offset) > 0: val1 = this1.val if this1 else 0 val2 = this2.val if this2 else 0 this.val = (val1 + val2 + offset) % 10 offset = int((val1 + val2 + offset )/ 10) this1 = this1.next if (this1 and this1.next) else None this2 = this2.next if (this2 and this2.next) else None if offset == 0 and not (this1 or this2): break else: nnode = ListNode() this.next = nnode this = this.next return this_head ``` ::: * 去除重複的數字 給定一個已經由小到大排列的 linked list,去除裡面重複出現的元素,只留下一個。也就是說,最後的結果會是一個由小到大排列且每個元素都不相同的 linked list。 ![](https://hackmd.io/_uploads/rJ51VX32Y.png) :::spoiler 解答 這題可以算是delete方法的應用:刪除linked list中不特定的元素。 ``` # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object): def deleteDuplicates(self, head): """ :type head: ListNode :rtype: ListNode """ x = head if x == None: return None while (x.next != None): if (x.next.val == x.val): x.next = x.next.next else: x = x.next return head ``` :::