算法與內置數據結構
- 常用算法和數據結構
- sorted
- dict/list/set/tuple
- 分析時間/空間復雜度
- 實現常見數據結構和算法
數據結構/算法 | 語言內置 | 內置庫 |
---|---|---|
線性結構 | list(列表)/tuple(元祖) | array(數組,不常用)/collection.namedtuple |
鏈式結構 | collections.deque(雙端隊列) | |
字典結構 | dict(字典) | collections.Counter(計數器)/OrderedDict(有序字典) |
集合結構 | set(集合)/frozenset(不可變集合) | |
排序算法 | sorted | |
二分算法 | bisect模塊 | |
堆算法 | heapq模塊 | |
緩存算法 | functors.lru_cache(Least Recent Used,python3) |
coolections模塊提供了一些內置數據結構的擴展
collections
Point = collections.namedtuple('Point','x','y')
p = Point(1,2)
namedtuple讓tuple屬性可讀
de = collections.deque()
de.append(1)
de.appendleft(0)
c = collections.Counter()
c = coolections.Counter('abcab')
python dict 底層結構
dict底層使用的哈希表
- 為了支持快速查找使用了哈希表作為底層結構
- 哈希表平均查找時間復雜度O(1)
- Cpython解釋器使用二次探查解決哈希沖突問題
python list/tuple區別
- 都是線性結構 支持下標訪問
- list是可變對象,tuple保存的引用不可變
t = ([1],2,3)
t[0].append(1)
t
([1,1],2,3)
保存的引用不可變指的是你沒法替換掉這個對象,但是如果對系那個本身是一個可變對象,是可以修改這個引用指向的可變對象的
- list沒發作為字典的key, tuple可以(可變對象不可hash)
什么是LRUCache?
Least-Recently-Used 替換掉最近最少使用的對象
- 緩存剔除策略,當緩存空間不夠用的時候需要一種方式剔除key
- 常見的有LRU, LFU等
- LRU通過使用一個循環雙端隊列不斷把最新訪問的key放到表頭實現
字典用來緩存,循環雙端鏈表用來記錄訪問順序
- 利用python內置的dict + collections.OrderedDict實現
- dict 用來當作k/v鍵值對的緩存
- OrderedDict用來實現更新最近訪問的key
from collections import OrderedDict
class LRUCache:
def __init__(self, capacity=128):
self.od = OrderedDict()
self.capacity = capacity
def get(self, key): #每次訪問更新最新使用的key
if key in self.od:
val = self.od[key]
self.od.move_to_end(key)
return val
else:
return -1
def put(self, key, value): # 更新k/v
if key in self.od:
del self.od[key]
self.od[key] = value # 更新key 到表頭
else: # insert
self.od[key] = value
# 判斷當前容量是否已經滿了
if len(self.od) > self.capacity:
self.od.popitem(last=False)
code/lrucache.py
算法常考點
排序+查找,重中之重
- 常考排序算法: 冒泡排序、快速排序、歸並排序、堆排序
- 線性查找,二分查找等
- 能獨立實現代碼(手寫), 能夠分析時間空間復雜度
python web 后端常考數據結構
- 常見的數據結構鏈表、隊列、棧、二叉樹、堆
- 使用內置結構實現高級數據結構,比如內置的list/deque實現棧
- leetcode或者《劍指offer》上的常見題
常考數據結構之鏈表
鏈表有單鏈表、雙鏈表、循環雙鏈表
- 如何使用python 來表示鏈表結構
- 實現鏈表常見操作,比如插入節點,反轉鏈表,合並多個鏈表等
- Leetcode練習常見鏈表題目
數據結構之鏈表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
pre = None
cur = head
while cur:
nextnode = cur.next
cur.next = pre
pre = cur
cur = nextnode
ruture pre
數據結構之隊列
隊列(queue)是先進先出結構
- 如何使用python實現隊列
- 實現隊列的apend和pop操作,如何做到先做先出
- 使用python的list或者collections.deque實現隊列
from collections import deque
class Queue:
def __init__(self):
self.items = deque()
def append(self, val):
retuen self.items.append(val)
def pop(self):
return self.items.popleft()
def empty(self):
return len(self.items) == 0
def test_queue():
q = Queue()
q.append(0)
q.append(1)
q.append(2)
print(q.pop())
print(q.pop())
print(q.pop())
test_queue()()
0
1
2
常考數據結構之棧
棧(stack)是后進先出結構
- 如何使用python實現棧?
- 實現棧的push 和 pop 操作, 如何做到后進先出
- 同樣可以用python list 或者collections.deque實現棧
from collections import deque
class Stack(object):
def __init__(self):
self.deque = deque() # 或者用list
def push(self, value):
self.deque.append(value)
def pop(self):
return self.deque.pop()
一個常考問題: 如何用兩個棧實現隊列?
常考數據結構之字典與集合
python dict/set 底層都是哈希表
- 哈希表的實現原理,底層其實就是一個數組
- 根據哈希函數快速定位一個元素,平均查找,非常快
- 不斷加入元素會引起哈希表重新開辟空間,拷貝之前元素到新數組