算法之迷宮問題
數據結構相關知識
一、什麽是數據結構?
數據結構是指相互之間存在著一種或多種關系的數據元素的集合和該集合中數據元素之間的關系組成。
簡單來說,數據結構就是設計數據以何種方式組織並存儲在計算機中。
比如:列表、集合與字典等都是一種數據結構。
“程序=數據結構+算法”
二、數據結構的分類
數據結構按照其邏輯結構可分為線性結構、樹結構、圖結構
- 線性結構:數據結構中的元素存在一對一的相互關系
- 樹結構:數據結構中的元素存在一對多的相互關系
- 圖結構:數據結構中的元素存在多對多的相互關系
下面就來說說線性結構,樹結構見鏈接,圖結構待續。。
三、線性結構
(1)棧
1、定義:棧是一個數據集合,可以理解為只能在一端進行插入或者刪除操作的列表。
2、棧的特點:後進先出(last-in,first-out),簡稱LTFO表
3、棧的概念:
- 棧頂:允許插入和刪除的這一端稱之為棧頂
- 棧底:另一固定的一端稱為棧底
- 空棧:不含任何元素的棧稱為空棧
4、棧的基本操作:
- 進棧(壓棧):push
- 出棧:pop
- 取棧頂:gettop
如圖:
5、棧的Python實現
不需要自己定義,使用列表結構即可。
- 進棧函數:append
- 出棧函數:pop
- 查看棧頂元素:li[-1]
li = [] li.append(1) li.append(2) li.append(3) print(li) print(li.pop()) print(li.pop())print(li.pop()) # print(li.pop()) #當棧空的時候就會報錯 # print(li[-1]) #查看棧頂元素
6、棧的應用----括號匹配問題
問題:給一個字符串,其中包含小括號,中括號,大括號,求該字符串中的括號是否匹配
例如:
()()[]{} 匹配
([{()}]) 匹配
[]( 不匹配
[(]) 不匹配
代碼如下:
# 方式一 def brace_match(s): ‘‘‘括號匹配問題‘‘‘ stack = [] # {()}[] match = {‘)‘: ‘(‘, ‘}‘: ‘{‘, ‘]‘: ‘[‘} match2 = {‘(‘: ‘)‘, "{": "}", "[": "]"} for ch in s: # print(i) if ch in {‘(‘, ‘{‘, ‘[‘}: # 如果左括號在裏面就把左括號添加進去,等待和右括號匹配 stack.append(ch) elif len(stack) == 0: # 如果再次進來括號的時候,這時候發現棧空了,說明缺少了左括號了 print(‘缺少了%s‘ % match[ch]) return False elif stack[-1] == match[ch]: # 比如棧頂元素是(,ch=‘)‘ stack.pop() else: print(‘括號不匹配‘) return False if len(stack) > 0: # 如果棧剩余了,說明缺少了右括號 print(‘缺少了%s‘ % match2[stack[-1]]) return False return ‘匹配成功‘ # 方式二 def check_kuohao(s): stack = [] for char in s: if char in {‘(‘, ‘[‘, ‘{‘}: stack.append(char) elif char == ‘)‘: if len(stack) > 0 and stack[-1] == ‘(‘: stack.pop() else: return False elif char == ‘]‘: if len(stack) > 0 and stack[-1] == ‘[‘: stack.pop() else: return False elif char == ‘}‘: if len(stack) > 0 and stack[-1] == ‘{‘: stack.pop() else: return False if len(stack) == 0: return True else: return False ret = brace_match(‘{()}]‘) print(ret) print(check_kuohao(‘{()}]‘))
(2)隊列
1、介紹
- 隊列是一個數據集合,僅允許在列表的一端進行插入,另一端進行刪除,
- 進行插入的一端稱為隊尾(rear),插入動作稱之為進隊或入隊
- 進行刪除的一端稱之為對頭(front),刪除動作稱為出隊
雙向隊列:對列的兩端都允許進行進隊和出隊操作
2、隊列的實現
隊列能否簡單用列表實現?為什麽?
- 初步設想:列表+兩個下標指針
- 創建一個列表和兩個變量,front變量指向隊首,rear變量指向隊尾。初始時,front和rear都為0。
- 進隊操作:元素寫到li[rear]的位置,rear自增1。
- 出隊操作:返回li[front]的元素,front自減1。
3、隊列的實現原理-----環形對列
環形隊列:當隊尾指針front == Maxsize + 1時,再前進一個位置就自動到0。
- 實現方式:求余數運算
- 隊首指針前進1:front = (front + 1) % MaxSize
- 隊尾指針前進1:rear = (rear + 1) % MaxSize
- 隊空條件:rear == front
- 隊滿條件:(rear + 1) % MaxSize == front
3、對列的內置模塊
使用方法:from collections import deque #deque是支持雙向隊列的
- 創建隊列:queue = deque(li)
- 進隊:append
- 出隊:popleft
- 雙向隊列隊首進隊:appendleft
- 雙向隊列隊尾進隊:pop
from collections import deque queue = deque()#創建隊列 queue.append(‘first‘) queue.append(‘second‘) queue.append(‘third‘) print(queue.popleft()) print(queue.popleft()) print(queue.popleft())#出隊,,先進先出 print([i for i in queue]) #查看隊列裏的元素 queue.appendleft(‘one‘)#雙向隊列隊首進隊 queue.appendleft(‘two‘)#雙向隊列隊首進隊 queue.appendleft(‘five‘)#雙向隊列隊首進隊 print(queue.pop()) print(queue.pop())#雙向隊列從隊尾出隊 print([i for i in queue]) #單向隊列 from queue import Queue q = Queue() q.put(‘a‘) q.put(‘b‘) q.put(‘c‘) print(q.get()) #a
(3)單鏈表
鏈表中每一個元素都是一個對象,每一個對象都是一個節點,包含有數據域key和指向下一個節點的指針next。通過各個節點之間的互相連接,最終串聯成一個列表
1、節點定義:
class Node(object): def __init__(self, item): self.item = item self.next = None
2、建立鏈表
頭插法
尾插法
3、鏈表的遍歷
4、鏈表節點的插入和刪除
# 插入: p.next = curNode.next curNode.next = p #刪除: p = curNode.next curNode.next = p.next #當前節點的下一個指向就指向他下一個的下一個 del p
插入:
刪除:
< >(4)雙鏈表
雙鏈表中的每個節點有兩個指針:一個指向後面節點、一個指向前面節點
1、節點定義:
class Node(object): def __init__(self,item): self.item = item #數據 self.next = None #下一個指向 self.prior = None #上一個指向
2、雙鏈表節點的插入和刪除
#插入 p.next = curNode.next curNode.next.prior = p p.prior = curNode curNode.next = p #刪除 p = curNode.next curNode.next = p.next p.next.prior = curNode del p
(1)
(2)
(3)
(4)
這四張圖片分別對應上面的四行代碼
(5)哈希表
哈希表(又稱為散列表),是一種線性表的存儲結構。哈希表由一個順序表(數組)和一個哈希函數組成。哈希函數h(k)將k作為自變量,返回元素的存儲下標。
1、簡單哈希函數
- 除法哈希:h(k) = k mod m #mod就是% #除留余數法
- 乘法哈希:h(k) = floor(m(kA mod 1)) 0<A<1 #floor是向下取整
假設有一個長度為7的數組,哈希函數h(k)=k%7。元素集合{14,22,3,5}的存儲方式如下圖。
2、哈希沖突
由於哈希表的大小是有限的,而要存儲的值的總數量是無限的,因此對於任何哈希函數,都會出現兩個不同元素映射到同一個位置上的情況 ,
這種情況叫做哈希沖突。
比如h(k)=k%7, h(0)=h(7)=h(14)=...
3、解決哈希沖突的辦法
- a、開放尋址法
- b、拉鏈發
開放尋址法:如果哈希函數返回的位置已經有值,則可以向後探查新的位置來存儲這個值。
- 線性探查:如果位置i被占用,則探查i+1, i+2,……
- 二次探查:如果位置i被占用,則探查i+12,i-12,i+22,i-22,……
- 二度哈希:有n個哈希函數,當使用第1個哈希函數h1發生沖突時,則嘗試使用h2,h3,……
拉鏈法:哈希表每個位置都連接一個鏈表,當沖突發生時,沖突的元素將被加到該位置鏈表的最後。
4、哈希表在Python中的應用
- a、字典與集合都是通過哈希表來實現的
- b、 在Python中的字典:a = {‘name‘: ‘Alex‘, ‘age‘: 18, ‘gender‘: ‘Man‘},使用哈希表存儲字典,通過哈希函數將字典的鍵映射為下標。
假設h(‘name’) = 3, h(‘age’) = 1, h(‘gender’) = 4,則哈希表存儲為[None, 18, None, ’Alex’, ‘Man’]
- c、在字典鍵值對數量不多的情況下,幾乎不會發生哈希沖突,此時查找一個元素的時間復雜度為O(1)。
算法之迷宮問題