一、在開始處插入
鏈表結構存在優於線性操作的幾種操作。再某些情況下,這些操作使得鏈表結構比數組更加合適。第一種情況就是在結構的開始處插入一項。如下:
# coding: utf-8 class Node(object): def __init__(self, data, next=None): self.data = data self.next = next head = None for count in range(1,6): head = Node(count, head) print head.data, head.next,head newItem = 100 head = Node(newItem, head)
下圖記錄了這個操作的兩種情況。在第一種情況下,head指針是None,因此向結構中插入了第1項。第2種情況下,將第2項插入到了同一結構的開頭處。
注意第2種情況,不需要復制數據並向下移動,並且不需要額外的內存。這意味着,在一個鏈表結構的開始處插入數據,時間和內存都是常數,這與數組的響應操作有所不同。
二、在行尾插入
在一個數組的行尾插入一項(python的oppend操作)需要的時間和內存都是常數,除非必須調整數組大小。對於單鏈表來說,在行尾插入一項必須考慮如下兩種情況:
- head指針為None,此時,將head指針設置為新的節點。
- head指針不為None,此時,代碼將搜索最后一個節點,並將其next指針指向新的節點。
第2種情況又回到遍歷模式。其形式如下:
# coding: utf-8 class Node(object): def __init__(self, data, next=None): self.data = data self.next = next head = None for count in range(1,4): # 為了盡量減少下圖的步驟,此處創建有3個節點的單鏈表 head = Node(count, head) print head.data, head.next,head newItem = 100 newNode = Node(newItem) if head is None: head = newNode else: probe = head while probe.next != None: probe = probe.next probe.next = newNode while head.next: head = head.next print head.data
這樣就在head鏈表末尾插入一個新的鏈接。該操作在時間上是線性的,在空間是是常數的。
三、在任何位置插入
在數組第i個位置插入一項,需要將從位置i到n+1的項都想下移動。因此,實際上是在當前位於i位置的項的前面插入了一項,從而讓新的項占據了i位置,而舊的項則占據了i+1的位置。
在一個鏈表中的第i個位置插入一項,也必須處理相同的情況。在i的位置插入一項,首先必須找到位置為i-1(如果i<n)或n-1(如果i>=n)的節點。然后考慮如下兩種情況:
- 該節點的next指針weiNone。意味着,i>=n,因此應該將新的項放在鏈表結構的末尾。
- 該節點的next指針不為None,意味着,0<i<n,因此必須將新的項放在位於i-1和i的節點之間。
和搜索第i項相同,插入操作必須計數節點,直到到達了想要的位置。然而,由於目標索引可能會大於或等於節點的數目,因此在搜索中,必須小心避免超出鏈表結構的末尾。為了解決這一問題,循環有一個額外的條件,就是測試當前節點的next指針,看看這個節點是否為最后一個節點。形式如下:
# coding: utf-8 class Node(object): def __init__(self, data, next=None): self.data = data self.next = next head = None for count in range(1,4): head = Node(count, head) print head.data, head.next,head index = 2 newItem = 100 if head is None or index <= 0: head = Node(newItem, head) else: probe = head while index > 1 and probe.next != None: probe = probe.next index -= 1 probe.next = Node(newItem, probe.next)
下圖展示了包含3個項的鏈表結構的第二個位置插入一項的情況。
和使用了遍歷模式的單鏈表結構操作一樣,這個操作也是線性的。然而,它使用的內存確是常數的。
結束!