一、連結串列和陣列
在編寫程式碼中,我們儲存的資料是儲存於記憶體當中,記憶體就像一塊塊並列排序的小方盒,每個小方盒都有自己地址,我們儲存的資料就在這樣一個個小方盒當中。
這些資料存放的結構有兩種基本方式,陣列和連結串列。
1,陣列
陣列在記憶體中是按順序,記憶體地址來儲存的,就好似上圖的抽屜,從上到下,按順序存放物品。這一特徵也就意味著資料在記憶體中是相連的,緊緊不分開的,小的記憶體空間可能會裝不下較多的資料,造成了記憶體空間浪費。
世界上許多事情有好有壞,有利有弊,陣列也是如此,資料在記憶體中緊密相連,也就意味著牽一髮而動全身,比如你想在陣列中新增一項資料,這就好比一排已經排好隊的士兵,每個人都有自己的編號,而此時你突然要插入其中。
你:“兄弟方便讓個位置嗎?”
你後面的士兵都一臉凶神惡煞地看著你,如果不是排長強力要求你插入其中,他們肯定不會讓你入隊,因為你的入隊,讓你身後的士兵的編號都要往後挪。
陣列也是一樣,當新加入一個資料時,這就意味著它後面的資料記憶體地址都要往後稍一稍,刪除亦如此。
2,連結串列 和賦值原理
連結串列和在記憶體中排列整齊的陣列不同,它們像一堆散兵遊勇,散佈於記憶體中,只要哪裡有空隙就往哪裡鑽,連結串列高效地運用了記憶體空間。雖然它們看起來雜亂無章,但其實它們井然有序,暗號讓它們緊緊相連。資料與資料之間有一條“暗號”的鏈子相連線,那個資料在首位,那個資料在第二位……在末尾都非常清楚。
這種“暗號”其實就是記憶體地址,如下圖,長方形就是節點,一個節點包含了兩個方面的內容,資料和“暗號”,這個“暗號”其實就是下一個節點的引用資訊。
連結串列的第一個和最後一個節點最重要和最特殊,最後一個節點則意味著後面沒有資料了,所以它指向None,第一個節點的記憶體地址需要一個地方來儲存,所以設立一個head屬性對第一個節點應用。
下面來實現節點程式碼,一個節點需要存放資料和對下一個資料的引用:
class Node:
def __init__(self,x):
self.data = initdata #存放資料
self.next = None #對下一個節點的引用
def getData(self): #返回資料
return self.data
def getNext(self): #返回下一個節點
return self.next
def setData(self,newdata):
self.data = newdata
def setNext(self,newnext):
self.next = newnext
相信很多人都有疑問,為什麼把下一個節點賦給上一個節點的next就實現了記憶體的引用呢?這與Python的特性有關,Python沒有專門的指標,所有變數即是指標。
舉一個例子,a = 6,一個簡單的賦值,它在記憶體中是怎樣實現的呢?
首先在記憶體中會建立資料6,資料6在記憶體中有自己的記憶體地址,然後再把變數標籤a指向6,如上圖a這個長方形中,實際是資料6的記憶體地址。再比如,a,b = b,a, 這實際就是a指向原來b指向的地址,b指向原來a指向的地址。明白了記憶體中賦值的原理,那麼對Python連結串列中,next = 下一個節點,就會很清晰了,next指向下一個節點的記憶體地址。
三,單連結串列的實現
1,連結串列的優點和缺點
連結串列插入和刪除資料非常快,但讀取資料非常慢
陣列 | 連結串列 | |
讀取 | O(1) | O(N) |
插入 | O(N) | O(1) |
刪除 | O(N) | O(1) |
陣列的讀取非常快,因為它在記憶體中連續儲存,插入和刪除慢,是因為插入和刪除都要改變相應的記憶體地址。
連結串列的插入和刪除都很快,因為只要相應的改變節點中next的指向即可,連結串列訪問一個特定資料時,必須沿著連結串列一個一個資料訪問,所以讀取很慢、
2,連結串列的方法
from node import Node class UnorderedList: def __init__(self): self.head = None def add(self,item): #新增資料 temp = Node(item) temp.setNext(self.head) #next指向表頭,head為引用表頭的資訊 self.head = temp #在把head指向新增加的節點 def size(self): #返回連結串列的size current =self.head count = 0 while current != None: count +=1 current = current.getNext() return count def search(self,item): #資料是否在連結串列中 current = self.head found = False while current != None and not found: if current.getData() == item: found = True else: current = current.getNext() return found def remove(self): #刪除某個資料 current = self.head previous = None found = False while not found: if current.getData == item: found = True else: previous = current current = current.getNext() if previous == None: self.head = current.getNext() else:
previous.setNext(current.getNext())