目錄
what's the 數據結構
數據結構是指相互之間存在着一種或多種關系的數據元素的集合和該集合中數據元素之間的關系組成。 簡單來說,數據結構就是設計數據以何種方式組織並存儲在計算機中。 比如:列表、集合與字典等都是一種數據結構。
通常情況下,精心選擇的數據結構可以帶來更高的運行或者存儲效率。數據結構往往同高效的檢索算法和索引技術有關。
數據結構按照其邏輯結構可分為線性結構、樹結構、圖結構:
-
- 線性結構:數據結構中的元素存在一對一的相互關系
- 樹結構:數據結構中的元素存在一對多的相互關系
- 圖結構:數據結構中的元素存在多對多的相互關系
下面我來重點來學習數據結構中比較重要的幾種:棧、隊列、鏈表、哈希表、二叉搜索樹
棧
棧(Stack)是一個數據集合,它是一種運算受限的線性表。其限制是僅允許在表的一端進行插入和刪除運算。這一端被稱為棧頂,相對地,把另一端稱為棧底。可以將棧理解為只能在一端進行插入或刪除操作的列表。
棧的特點:后進先出、先進后出(類似於往箱子里放東西,要拿的時候只能拿最上面的而最上面的是最后進的)
棧操作:進棧push、出棧pop、取棧頂gettop(在Python中,不用自定義棧,直接用列表就行,進棧函數:append 出棧函數:pop 查看棧頂函數:li[-1])
棧的應用
棧可以應用在處理括號匹配問題——括號匹配問題:給一個字符串,其中包含小括號、中括號、大括號,求該字符串中的括號是否匹配。
基本思路:按順序遍歷字符串是左括號則進棧,來的是右括號則將棧頂左括號pop,若來的右括號與棧頂左括號不匹配或空棧情況下來了右括號則返回錯誤信息
def brace_match(s): stack = [] match = {')':'(', ']':'[', '}':'{'} match2 = {'(':')', '[':']', '{':'}'} for ch in s: if ch in {'(', '[', '{'}: stack.append(ch)#左括號入棧 elif len(stack) == 0: print("缺少%s" % match[ch])#棧空了,但卻來了一個右括號 return False elif stack[-1] == match[ch]:#棧頂左括號與來的右括號相匹配 stack.pop()#出棧 else: print("括號不匹配") return False if len(stack) > 0:#全部操作完后棧內還有剩余左括號 print("缺少%s" % (match2[stack[-1]]))#顯示棧頂左括號對應的右括號 return False print('合法') return True brace_match("[{()[]}{}{}")#缺少]
隊列
隊列(Queue)是一個數據集合,僅允許在列表的一端進行插入,另一端進行刪除。 進行插入的一端稱為隊尾(rear),插入動作稱為進隊或入隊;進行刪除的一端稱為隊頭(front),刪除動作稱為出隊。和棧一樣,隊列是一種操作受限制的線性表。
隊列的性質:先進先出(可以將隊列理解為排隊買東西)
特殊情況——雙向隊列:隊列的兩端都允許進行進隊和出隊操作。
如何用列表實現隊列:
- 初步設想:列表+兩個下標指針
- 創建一個列表和兩個變量,front變量指向隊首,rear變量指向隊尾。初始時,front和rear都為0。
- 進隊操作:元素寫到li[rear]的位置,rear自增1。
- 出隊操作:返回li[front]的元素,front自減1。
以上就是隊列實現的基本思路,但是其實隊列的實現原理是一個環形隊列
環形隊列:當隊尾指針front == Maxsize + 1時,再前進一個位置就自動到0。
- 實現方式:求余數運算
- 隊首指針前進1:front = (front + 1) % MaxSize
- 隊尾指針前進1:rear = (rear + 1) % MaxSize
- 隊空條件:rear == front
- 隊滿條件:(rear + 1) % MaxSize == front
在Python中,有一個內置模塊可以幫我們快速建立起一個隊列——deque模塊
""" 使用方法:from collections import deque 創建隊列:queue = deque(li) 進隊:append() 出隊:popleft() 雙向隊列隊首進隊:appendleft() 雙向隊列隊尾進隊:pop() """
棧和隊列的知識點應用:
用棧和隊列的知識來解決迷宮問題:http://www.cnblogs.com/zhuminghui/p/8414307.html
鏈表
鏈表中每一個元素都是一個對象,每個對象稱為一個節點,包含有數據域key和指向下一個節點的指針next。通過各個節點之間的相互連接,最終串聯成一個鏈表。
#結點的定義 class Node(object): def __init__(self, item): self.item = item self.next = None
建立鏈表的方式有頭插法和尾插法兩種
- 頭插法:在一個結點的前面插入元素,head的指針由指向原來的結點變為指向新元素,新元素的指針指向原來的結點
- 尾插法:在一個元素后面插入一個元素,原來結點的指針指向新元素
建立列表實現代碼如下:
#定義結點 class Node: def __init__(self, data): self.data = data self.next = None #頭插法 def create_linklist(li): head = None for num in li: node = Node(num) node.next = head head = node return head #尾插法 def create_linklist_tail(li): head = None if not li: return head head = Node(li[0]) tail = head for num in li[1:]: node = Node(num) tail.next = node tail = node return head def print_linklist(head): node = head while node: print(node.data) node = node.next linklist = create_linklist_tail([1,2,3,4]) print_linklist(linklist)

#curNode為A結點 c.next = curNode.next curNode.next = c

#p為要刪除的結點 p = curNode.next curNode.next = curNode.next.next#即p.next del p
class Node(object): def __init__(self, item=None): self.item = item self.next = None self.prior = None
雙向鏈表結點的插入

#p為新插入的元素 p.next = curNode.next curNode.next.prior = p p.prior = curNode curNode.next = p
#p為要刪除的結點 p = curNode.next curNode.next = p.next p.next.prior = curNode del p
- 按元素值查找——O(n),因為沒有下標所以沒法做二分
- 按下標查找——O(n),因為沒有下標
- 在某元素后插入——O(1)
- 刪除某元素——O(1)
哈希表(Hash Table,又稱為散列表),是一種線性表的存儲結構。哈希表由一個順序表(數組)和一個哈希函數組成。哈希函數h(k)將元素k作為自變量,返回元素的存儲下標。
假設有一個長度為7的數組,哈希函數h(k)=k%7。元素集合{14,22,3,5}的存儲方式如下圖。

哈希沖突:
由於哈希表的大小是有限的,而要存儲的值的總數量是無限的,因此對於任何哈希函數,都會出現兩個不同元素映射到同一個位置上的情況,這種情況叫做哈希沖突。
比如上圖中的哈希表就存在這哈希沖突——h(k)=k%7, h(0)=h(7)=h(14)=...
- 線性探查:如果位置i被占用,則探查i+1, i+2,……
- 二次探查:如果位置i被占用,則探查i+12,i-12,i+22,i-22,……
- 二度哈希:有n個哈希函數,當使用第1個哈希函數h1發生沖突時,則嘗試使用h2,h3,……

哈希表在Python中的應用
#字典與集合都是通過哈希表來實現的 #在Python中的字典: a = {'name': 'Damon', 'age': 18, 'gender': 'Man'} #使用哈希表存儲字典,通過哈希函數將字典的鍵映射為下標。假設h(‘name’) = 3, h(‘age’) = 1, h(‘gender’) = 4,則哈希表存儲為[None, 18, None, ’Damon’, ‘Man’] #在字典鍵值對數量不多的情況下,幾乎不會發生哈希沖突,此時查找一個元素的時間復雜度為O(1)。