學習筆記,僅供參考,有錯必糾
算法與數據結構–基於python
鏈表
爲啥需要鏈表
順序表的構建需要預先知道數據大小來申請連續的存儲空間,而在進行擴充時又需要進行數據的搬遷,所以使用起來不是很靈活;而鏈表結構可以充分利用計算機內存空間,實現靈活的內存動態管理。
什麼是鏈表
鏈表結構可以充分利用計算機內存空間,實現靈活的內存動態管理,鏈表是一種常見的基礎數據結構,是一種線性表,但是不像順序表一樣連續存儲數據,而是在每一個結點(數據存儲單元)裏存放下一個結點的位置信息(即地址)。
單向鏈表
什麼是單向鏈表
單向鏈表也叫單鏈表,是鏈表中最簡單的一種形式;它的每個結點包含兩個域,一個信息域(元素域)和一個鏈接域;這個鏈接指向鏈表中的下一個結點,而最後一個結點的鏈接域則指向一個空值。
- 圖示
單鏈表也可以沒有頭結點,如果沒有頭結點的話,那麼單鏈表就會變成這樣:
- 關於頭結點
頭結點是爲了操作的統一與方便而設立的,放在第一個元素結點之前,其數據域一般無意義(當然有些情況下也可存放鏈表的長度、用做監視哨等等),首元結點也就是第一個元素的結點,它是頭結點後邊的第一個結點,頭結點不是鏈表所必需的。
- 關於頭指針
在線性表的鏈式存儲結構中,頭指針是指鏈表指向第一個結點的指針,若鏈表有頭結點,則頭指針就是指向鏈表頭結點的指針;頭指針具有標識作用,故常用頭指針冠以鏈表的名字;無論鏈表是否爲空,頭指針均不爲空,頭指針是鏈表的必要元素。
單列表的操作
is_empty()
#鏈表是否爲空
length()
#鏈表長度
travel()
#遍歷整個鏈表
append(item)
#鏈表尾部添加元素
add(item)
#鏈表頭部添加元素
insert(pos, item)
#指定位置添加元素
search(item)
#查找結點是否存在
remove(item)
#刪除結點
節點的實現
class Node:
def __init__(self, elem):
#初始化數據區
self.elem = elem
#初始化鏈接區
self.next = None
單鏈表的實現
首先,我們參照下圖中的鏈表形式,來構造我們的單鏈表:
同時,我們參照下圖中的尾插法,在我們的鏈表末尾插入數據:
參照下圖中的頭插法,在鏈表頭部添加元素:
參照下圖中的插入法,在鏈表中指定位置插入元素:
參照下圖中的刪除法,在鏈表中刪除某個指定元素:
定義單鏈表:
class SingleLinkedList:
def __init__(self):
#頭指針
self.__head = None
#判斷鏈表是否爲空
def is_empty(self):
return self.__head is None
#查詢長度
def length(self):
#判斷是否爲空
if self.is_empty():
return 0
else:
#定義遊標
cur = self.__head
#計數
count = 0
while cur != None:
cur = cur.next
count += 1
return count
#遍歷鏈表
def travel(self):
if self.is_empty():
return
else:
#定義遊標
cur = self.__head
while cur != None:
#打印數據
print(cur.elem, " ")
cur = cur.next
print('')
#鏈表尾部添加元素
def append(self, item):
#定義新節點
node = Node(item)
#判斷鏈表是否爲空
if self.is_empty():
self.__head = node
else:
cur = self.__head
while cur.next!= None:
cur = cur.next
#while循環結束後,cur到達了最後一個節點
cur.next = node
#鏈表開頭插入
def add(self, item):
#新節點
node = Node(item)
if self.is_empty():
self.__head = node
else:
node.next = self.__head
self.__head = node
#鏈表中指定位置插入
def insert(self, pos, item):
#新節點
if pos < 0:
self.add(item)
elif pos > (self.length() - 1):
self.append(item)
else:
node = Node(item)
pre = self.__head
count = 0
while count < (pos -1):
pre = pre.next
count += 1
#下面的兩行代碼順序不可變
node.next = pre.next
pre.next = node
#查找節點
def search(self, item):
if self.is_empty():
return False
else:
cur = self.__head
while cur!= None:
if cur.elem == item:
return True
else:
cur = cur.next
return False
#刪除節點
def remove(self,item):
if self.is_empty():
return
else:
# 定義cur遊標
cur = self.__head
# 定義pre遊標
pre = None
# 查找所有的位置有沒有要刪除的,若有則刪
while cur != None:
# 判斷cur指向的數據,是否爲要刪的數據
if cur.elem == item:
# 考慮特殊情況,恰好要刪的是第一個元素
if cur == self.__head:
# 頭結點指向後一個結點
self.__head = cur.next
else:
# 刪除
pre.next = cur.next
return
else:
# 移動遊標,先移動pre,再移動cur
pre = cur
cur = cur.next
測試:
if __name__ == "__main__":
sll = SingleLinkedList()
print(sll.is_empty())
print(sll.length())
print('-'*20)
sll.travel()
print('-'*20)
sll.append(1)
sll.add(2)
sll.append(3)
sll.travel()
print('-'*20)
print(sll.is_empty())
print(sll.length())
print('-'*20)
sll.insert(1,'abc')
sll.travel()
print(sll.search(2))
print('-'*20)
sll.remove('abc')
sll.travel()
輸出:
True
0
--------------------
--------------------
2
1
3
--------------------
False
3
--------------------
2
abc
1
3
True
--------------------
2
1
3
鏈表與順序表的對比
鏈表與順序表各種操作的時間複雜度:
操作 | 鏈表 | 順序表 |
---|---|---|
訪問元素 | O(n) | O(1) |
在頭部插入/刪除 | O(1) | O(n) |
在尾部插入/刪除 | O(n) | O(1) |
在中間插入/刪除 | O(n) | O(n) |