列表(其餘語言稱數組)是一種基本數據結構。python
c的數組和python的列表有兩點不一樣:linux
(1)數組元素類型要相同,列表元素類型能夠不同。數組
python存的不是真實的值而是存的內存地址。安全
32位機器上一個地址佔4個字節,64位機器上一個地址佔用8個字節。數據結構
(2)數組長度固定,python是長度不夠了就自動開新的內存地址,把原來的內容拷過來。app
append:不考慮python作得複製操做,大概是O(1)學習
insert:時間複雜度是O(n),在插入後,後面的元素都要日後挪動。spa
pop\remove:pop最後一個是O(1),寫了參數則是O(n),前面的刪了後,後面的都要往前挪。線程
棧的定義:棧是一個數據集合,能夠理解爲只能在一端進行插入或刪除操做的列表。指針
棧的特色:後進先出(last-in,first-out), 簡稱LIFO表。相似一摞書:
棧的概念:
棧頂:容許插入和刪除的這一端稱爲棧頂。
棧底:另外固定的這一端稱爲棧底。
空棧:不含任何元素的棧稱爲空棧。
棧的基本操做:
進棧(壓棧):push
出棧:pop
取棧頂:gettop(查看棧頂元素,但不取走) li[-1]
使用通常的列表結構便可實現棧:
class Stack: """棧""" def __init__(self): self.stack = [] def push(self, element): self.stack.append(element) def pop(self): if len(self.stack) > 0: return self.stack.pop() else: print("棧已經空了") def get_top(self): if len(self.stack) > 0: # 判斷棧是否爲空 return self.stack[-1] else: return None stack = Stack() stack.push(1) stack.push(2) stack.push(6) print(stack.pop()) # 6
更簡單的方式實現棧的方法:建立一個列表,只使用append和pop方法進行操做。
括號匹配問題:給一個字符串,其中包含小括號、中括號、大括號,求該字符串中的括號是否匹配。
例如:
()()[]{} 匹配 ([{()}]) 匹配 []( 不匹配 [(]) 不匹配
代碼實現以下所示:
class Stack: """棧""" def __init__(self): self.stack = [] def push(self, element): self.stack.append(element) def pop(self): if len(self.stack) > 0: return self.stack.pop() else: print("棧已經空了") def get_top(self): if len(self.stack) > 0: # 判斷棧是否爲空 return self.stack[-1] else: return None def is_empty(self): """判斷是否爲空""" return len(self.stack) == 0 def brace_match(s): """括號匹配""" match = {'}':'{', ']':'[', ')':'('} # 右括號爲鍵,左括號爲值 stack = Stack() for ch in s: # 獲取一個個字符 if ch in {'(','[','{'}: stack.push(ch) else: # ch in {')',']','}'} if stack.is_empty(): # 若是棧爲空 return False elif stack.get_top() == match[ch]: stack.pop() else: # stack.get_top() != match[ch] return False if stack.is_empty(): # 若是棧是空的了 return True else: return False print(brace_match('(){}[{()}]')) # True print(brace_match('(){}[{[(])}]')) # False
隊列是一個數據集合,僅容許在列表的一端進行插入,另外一端進行刪除。
進行插入的一端稱爲隊尾(rear),插入動做稱爲進隊或入隊。
進行刪除的一端稱爲隊頭(front),刪除動做稱爲出隊。
隊列的性質:先進先出(First-in,First-out)
初步設想:列表+兩個下標指針;建立一個列表和兩個變量,front變量指向隊首,rear變量指向隊尾。初始時,front和rear都爲0。
進隊操做:元素寫到li[rear]的位置,rear自增1。
出隊操做:返回li[front]的元素,front自減1。
這種實現方式很差,在一次次增減中,前面的大量內存空間都被浪費了。
實現方式:取餘數運算
注意:隊滿狀態下還空着一個位子,之因此不填上,是爲了防止不能判別出來隊究竟是空的仍是滿的。
環形隊列:當隊尾指針front == Maxsize - 1時,再前進一個位置就自動到0。
class Queue: """隊列""" def __init__(self, size=100): self.queue = [0 for _ in range(size)] # 建立固定長的列表做爲隊列 self.size = size self.rear = 0 # 隊尾指針 self.front = 0 # 隊首指針 def push(self, element): """進隊""" if not self.is_filled(): self.rear = (self.rear + 1) % self.size # 隊尾指針前進一 self.queue[self.rear] = element # 添加元素 else: raise IndexError("Queue is filled") def pop(self,): """出隊""" if not self.is_empty(): self.front = (self.front + 1) % self.size # 隊首指針前進1 return self.queue[self.front] # 返回新的front值 else: raise IndexError("Queue is empty") # 隊列爲空拋出錯誤 def is_empty(self): """判斷隊空""" return self.rear == self.front # 隊空條件:rear == front def is_filled(self): """判斷隊滿""" return (self.rear + 1) % self.size == self.front # 隊滿條件:(rear + 1) % MaxSize == front q = Queue(5) for i in range(4): q.push(i) print(q.is_filled()) # True print(q.pop()) # 0 q.push(3) print(q) # <__main__.Queue object at 0x10401ae48>
雙向隊列的兩端都支持進隊和出隊操做。
雙向隊列的基本操做:隊首進隊/隊首出隊、隊尾進隊/隊尾出隊。
以前學習過的queue是用來保證線程安全的,使用方法:from collections import deque,在collections中有一些數據結構,其中就包含了deque(雙向隊列)。
from collections import deque """ deque([iterable[, maxlen]]) 參數:列表、最大隊列 """ # q = deque() # 建立隊列 q = deque([1,2,3], 5) q.append(1) # 隊尾進隊 print(q.popleft()) # 1 隊首出隊 # 用於雙向隊列 q.appendleft(1) # 隊首進隊 q.pop() # 隊尾出隊
可使用這個內置模塊來模擬一個linux系統的tail命令來讀取文件的最後幾行:
from collections import deque def tail(n): with open('test.txt', 'r') as f: q = deque(f, n) return q for line in tail(5): print(line, end='') """ 23e234 2342352 dfe232 dwwdwewew wedwewf """