一.內存node
- 計算機的做用:對數據進行存儲和運算。首先咱們須要知道咱們目前使用的計算機都是二進制的計算機,就覺得着計算機只能夠存儲和運算二進制的數據。例以下載好的一部電影,該電影能夠存儲到計算機中,計算機中存儲的是基於二進制的電影數據,而後咱們能夠經過相關的視頻播放軟件結合相關的硬件對電影的二進制數據進行相關的運算操做,所產生的結果就是咱們能夠看到電影的畫面和聽到音頻的聲音。面試
- 問題:闡述計算機如何計算1+2的結果?編程
- 闡述:簡單理解爲,首先能夠將1和2輸入到計算機中,而後計算機會將1和2轉換成二進制的數據進行數據存儲,而後經過加法器進行兩個二進制數值的計算並返回結果。數據結構
- 分析:上述的闡述中提到,計算機首先須要存儲1和2這兩個數值,那麼計算機如何進行數據的存儲呢?那麼毫無疑問,計算機能夠將數據直接存儲到內存中。app
- 變量:咱們在編程世界中,能夠將某個數值直接賦值給一個變量,可是最終數值會被存儲到計算機的內存中,所以咱們能夠理解爲,變量表示的就是計算機中進行數據存儲的某一塊內存。測試
- 如何形象化的理解計算機的內存?spa
- 舉例:將計算機的內存空間映射到咱們現實生活中的話,內存就比如是咱們在現實生活中三維立體的空間。生活在北京的北漂們,幾乎都居住的是一個獨立的公寓或者合租在一個幾居室的某一個房間中,那麼北漂甲就比如是數據,而他所居住的房間則就是存儲數據的一塊內存空間。3d
- 分析:從上述案例中,咱們能夠得知北漂甲居住的房間會有兩個基本的屬性,其一就是房間空間的大小,其二就是房間的一個位置標識(門牌號)。那麼計算機中存儲數據的內存空間也會有這兩個最基本的屬性:內存空間大小和內存空間的地址。內存空間的大小能夠表示該空間能夠存儲數據值的大小範圍,內存空間的地址(用十六進制數值表示)能夠用來經過尋址定位、查找到該內存空間中所存儲的數據值。code
- 如何理解 a = 10 這條賦值語句對應的內存圖呢?視頻
- 引用:當一個變量中存儲的是某一塊內存空間的地址,則該變量便可成爲那塊內存空間的引用。a=10,a就是10所在內存空間的一個引用。
- 指向:當一個變量中存儲了一塊內存空間的地址,則稱該變量(引用)指向了那塊內存。
- 不一樣類型數據佔用內存空間的大小:整形(4字節),浮點型(8字節),字符型(1字節)
二.順序表:集合中存儲的元素是有順序的。順序表的結構能夠分爲兩種形式:單數據類型和多數據類型。
- 單數據類型:在內存中如何存儲 int a = 10,20,30,如何取得每個數據值呢?
- 多數據類型:在內存中如何存儲 li = 10,'a',96.5,如何獲取每個數據值呢?
- 順序表的弊端:順序表的結構須要預先知道數據大小來申請連續的存儲空間,而在進行擴充時又須要進行數據的搬遷。
- Python中的 list 和 tuple 兩種類型採用了順序表的實現技術。
三.鏈表:相對於順序表,鏈表結構能夠充分利用計算機內存空間,實現靈活的內存動態管理。
- 鏈表(Linked list)是一種常見的基礎數據結構,是一種線性表,可是不像順序表同樣連續存儲數據,而是每個結點(數據存儲單元)裏存放下一個結點的信息(即地址):
- 一、單向鏈表
單向鏈表也叫單鏈表,是表中最簡單的一種形式,它的每一個節點包含兩個域,一個信息域(元素域)和一個連接域。這個連接指向鏈表中的下一個節點,而最後一個節點的連接域則指向一個空值。
- 表中元素elem用來存放具體的數據。
- 連接域next用來存放下一個節點的位置。
- 變量p指向鏈表的頭節點(首節點)的位置,從p出發能找到表中的任意節點。
- 單向鏈表的抽象數據類型定義:
. is_empty():鏈表是否爲空
. length():鏈表長度
. travel():遍歷整個鏈表
. add(item):鏈表頭部添加元素
. append(item):鏈表尾部添加元素
. insert(pos, item):指定位置添加元素
. remove(item):刪除節點
. search(item):查找節點是否存在
- 代碼實現:
class Node(): def __init__(self,item): self.item = item self.next = None def __str__(self): return str(self.item) class Link(): def __init__(self): #永遠指向鏈表中第一個節點 self._head = None def isEmpty(self): return self._head is None def add(self,item): node = Node(item) node.next = self._head self._head = node def length(self): count = 0 if self.isEmpty(): return count else: cur = self._head while cur is not None: count += 1 cur = cur.next return count def travel(self): cur = self._head while cur is not None: print(cur) cur = cur.next def append(self,item): node = Node(item) cur = self._head if self.isEmpty(): self._head = node else: while cur is not None: #由於循環遍歷結束後cur會指向空並不是最後一個節點 pre_cur = cur cur = cur.next pre_cur.next = node def search(self,item): ex = False cur = self._head while cur is not None: if cur.item == item: ex = True break cur = cur.next return ex def insertTo(self,item,index): cur = self._head ex = 0 node = Node(item) #插入到第一個節點位置 if index <= 0: self.add(item) #插入到最後一個節點位置 elif index >= self.length(): self.append(item) else: while cur is not None: pre = cur cur = cur.next #此處插入的必定不是第一個節點和最後一個節點位置,所以index要減1 if ex == index-1: node.next = cur pre.next = node break ex += 1 def remove(self,item): pre = None cur = self._head #刪除的是第一個節點 if cur.item == item: self._head = cur.next else: while cur is not None: pre = cur cur = cur.next if cur.item == item: pre.next = cur.next cur.next = None cur = cur.next #測試代碼 link = Link() link.add('bobo') link.add('jay') link.add('tom') link.add('jerry') # print(link.search('tom')) # link.insertTo('haha',1) link.remove('bobo') link.travel()
- 2.單向循環鏈表:單鏈表的一個變形是單向循環鏈表,鏈表中最後一個節點的next域再也不爲None,而是指向鏈表的頭結點。
- 基本操做和單鏈表基本同樣,實現代碼以下:
# coding=utf-8 # 單向循環鏈表 class Node: """節點""" def __init__(self, item): self.item = item self.next = None def __str__(self): return str(self.item) class SinCycLinkedList: """單向循環鏈表""" def __init__(self): self._head = None def is_empty(self): """判斷鏈表是否爲空""" return self._head is None def length(self): """鏈表長度""" if self.is_empty(): return 0 count = 1 cur = self._head while cur.next != self._head: # print("cur", cur.item) count += 1 cur = cur.next return count def travel(self): """遍歷""" if self.is_empty(): return cur = self._head print(cur.item) while cur.next != self._head: cur = cur.next print(cur.item) def add(self, item): """在頭部添加一個節點""" node = Node(item) if self.is_empty(): self._head = node node.next = self._head else: node.next = self._head cur = self._head while cur.next != self._head: cur = cur.next cur.next = node self._head = node def append(self, item): """在尾部添加一個節點""" node = Node(item) if self.is_empty(): self._head = node node.next = self._head else: cur = self._head # print(type(cur), cur.item, cur.next) while cur.next != self._head: cur = cur.next # print(cur.item) cur.next = node node.next = self._head def insert(self, pos, item): """指定位置pos添加節點""" if pos <= 0: self.add(item) elif pos > (self.length() - 1): self.append(item) else: node = Node(item) cur = self._head cur_pos = 0 while cur.next != self._head: if (pos - 1) == cur_pos: node.next = cur.next cur.next = node break cur_pos += 1 cur = cur.next def remove(self, item): """刪除一個節點""" if self.is_empty(): return pre = self._head # 刪除首節點 if pre.item == item: cur = pre while cur.next != self._head: cur = cur.next cur.next = pre.next # 刪除首節點(跳過該節點) self._head = pre.next # 從新指定首節點 # 刪除其餘的節點 else: cur = pre while cur.next != self._head: if cur.next.item == item: cur.next = cur.next.next cur = cur.next def search(self, item): """查找節點是否存在""" if self.is_empty(): return -1 cur_pos = 0 cur = self._head if cur.item == item: return cur_pos while cur.next != self._head: if cur.item == item: return cur_pos cur_pos += 1 cur = cur.next if cur_pos == self.length() - 1: return -1 if __name__ == "__main__": ll = SinCycLinkedList() ll.add(1) # 1 ll.add(2) # 2 1 # ll.travel() ll.append(3) # 2 1 3 ll.insert(2, 4) # 2 1 4 3 ll.insert(4, 5) # 2 1 4 3 5 ll.insert(0, 6) # 6 2 1 4 3 5 print("length:", ll.length()) # 6 ll.travel() # 6 2 1 4 3 5 print("search(3)", ll.search(3)) # 4 print("search(7)", ll.search(7)) # -1 print("search(6)", ll.search(6)) # 0 print("remove(1)") ll.remove(1) print("length:", ll.length()) # 6 2 4 3 5 print("remove(6)") ll.remove(6) ll.travel()
3.雙向鏈表:一種更復雜的鏈表是 "雙向鏈表" 或 "雙面鏈表"。每一個節點有兩個連接:一個指向前一個節點,當次節點爲第一個節點時,指向空值;而另外一個指向下一個節點,當此節點爲最後一個節點時,指向空值。
- 代碼實現:
# coding=utf-8 # 雙向鏈表 class Node: """節點""" def __init__(self, item): self.item = item self.prev = None self.next = None class DLinkList: """雙向鏈表""" 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 = 1 while cur.next is not None: count += 1 cur = cur.next return count def travel(self): """遍歷鏈表""" print("↓↓" * 10) if self.is_empty(): print("") else: cur = self._head print(cur.item) while cur.next is not None: cur = cur.next print(cur.item) print("↑↑" * 10) def add(self, item): """鏈表頭部添加節點""" node = Node(item) if self.is_empty(): self._head = node else: cur = self._head node.next = cur cur.prev = node self._head = node def append(self, item): """鏈表尾部添加節點""" node = Node(item) if self.is_empty(): self._head = node else: cur = self._head # 遍歷找到最後一個節點 while cur.next is not None: cur = cur.next # 在尾節點添加新的節點 cur.next = node node.prev = cur def insert(self, pos, item): """指定位置添加""" # 頭部添加 if pos <= 0: self.add(item) # 尾部添加 elif pos > (self.length() - 1): self.append(item) # 其餘位置添加 else: node = Node(item) cur = self._head cur_pos = 0 while cur.next is not None: if cur_pos == (pos - 1): # 與下一個節點互相指向 node.next = cur.next cur.next.prev = node # 與上一個節點互相指向 cur.next = node node.prev = cur cur_pos += 1 cur = cur.next def remove(self, item): """刪除節點""" if self.is_empty(): return else: cur = self._head # 刪除首節點 if cur.item == item: self._head = cur.next cur.next.prev = None # 刪除其餘節點 else: while cur.next is not None: if cur.item == item: # 刪除以前:1 ←→ [2] ←→ 3 # 刪除以後:1 ←→ 3 cur.prev.next = cur.next cur.next.prev = cur.prev cur = cur.next # 刪除尾節點 if cur.item == item: cur.prev.next = None def search(self, item): """查找節點是否存在""" if self.is_empty(): return -1 else: cur = self._head cur_pos = 0 while cur.next is not None: if cur.item == item: return cur_pos cur_pos += 1 cur = cur.next if cur_pos == (self.length() - 1): return -1 if __name__ == "__main__": ll = DLinkList() ll.add(1) # 1 ll.add(2) # 2 1 ll.append(3) # 2 1 3 ll.insert(2, 4) # 2 1 4 3 ll.insert(4, 5) # 2 1 4 3 5 ll.insert(0, 6) # 6 2 1 4 3 5 print("length:", ll.length()) # 6 ll.travel() # 6 2 1 4 3 5 print("search(3)", ll.search(3)) print("search(4)", ll.search(4)) print("search(10)", ll.search(10)) ll.remove(1) print("length:", ll.length()) ll.travel() print("刪除首節點 remove(6):") ll.remove(6) ll.travel() print("刪除尾節點 remove(5):") ll.remove(5) ll.travel()
- 面試題:如何將單鏈表倒序?
def reverse(self): if self._head: cur = self._head pre = None cur_next = cur.next if cur.next is None: return while True: cur.next = pre pre = cur cur = cur_next if cur == None: self._head = cur break cur_next = cur_next.next self._head = pre