堆:
①堆通常是一個可以被看做一棵樹的數組對象。堆總是滿足下列性質:
·堆中某個節點的值總是不大於或不小於其父節點的值;
·堆總是一棵完全二叉樹。將根節點最大的堆叫做最大堆或大根堆,根節點最小的堆叫做最小堆或小根堆。常見的堆有二叉堆、斐波那契堆等。
②堆是在程序運行時,而不是在程序編譯時,申請某個大小的內存空間。即動態分配內存,對其訪問和對一般內存的訪問沒有區別。
③堆是應用程序在運行的時候請求操作系統分配給自己內存,一般是申請/給予的過程。
④堆是指程序運行時申請的動態內存,而棧只是指一種使用堆的方法(即先進后出)。
堆的應用:
#堆排序 def sift(li, left, right): i = left j = 2 * i + 1 tmp = li[left] while j <= right: if j+1 <= right and li[j] < li[j+1]: j = j + 1 if tmp < li[j]: li[i] = li[j] i = j j = 2 * i + 1 else: break li[i] = tmp def heap_sort(li): n = len(li) for i in range(n//2-1, -1, -1): #建立堆 sift(li, i, n-1) for i in range(n-1, -1, -1): #挨個出數 li[0], li[i] = li[i],li[0] sift(li, 0, i-1) li = [6,8,1,9,3,0,7,2,4,5] heap_sort(li) print(li)
棧:
①棧(stack)又名堆棧,一個數據集合,可以理解為只能在一端進行插入或刪除操作的列表。其限制是僅允許在表的一端進行插入和刪除運算。這一端被稱為棧頂,相對地,把另一端稱為棧底。
②棧就是一個桶,后放進去的先拿出來,它下面本來有的東西要等它出來之后才能出來(先進后出)
③棧(Stack)是操作系統在建立某個進程時或者線程(在支持多線程的操作系統中是線程)為這個線程建立的存儲區域,該區域具有FIFO的特性,在編譯的時候可以指定需要的Stack的大小。
棧的基本操作:
進棧(壓棧):push
出棧:pop
取棧頂:gettop
用python實現堆棧
# 后進先出 class Stack(): def __init__(self,size): self.size=size self.stack=[] self.top=-1 def push(self,x): if self.isfull(): raise exception("stack is full") else: self.stack.append(x) self.top=self.top+1 def pop(self): if self.isempty(): raise exception("stack is empty") else: self.top=self.top-1 self.stack.pop() def isfull(self): return self.top+1 == self.size def isempty(self): return self.top == '-1' def showStack(self): print(self.stack) s=Stack(10) for i in range(5): s.push(i) s.showStack() for i in range(3): s.pop() s.showStack() """ 類中有top屬性,用來指示棧的存儲情況,初始值為1,一旦插入一個元素,其值加1,利用top的值樂意判定棧是空還是滿。 執行時先將0,1,2,3,4依次入棧,然后刪除棧頂的前三個元素 """
棧的應用——括號匹配問題
括號匹配問題:給一個字符串,其中包含小括號、中括號、大括號,求該字符串中的括號是否匹配。例如:
()()[]{} 匹配
([{()}]) 匹配
[]( 不匹配
[(]) 不匹配

def kuohao_match(exp): stack = [] di = {'(':')', '{':'}', '[':']'} for c in exp: if c in {'(','{', '['}: stack.append(c) else: if len(stack) == 0: return False top = stack.pop() if di[top] != c: return False if len(stack) > 0: return False else: return True print(kuohao_match('()[]{([]][]}()'))
棧的應用——迷宮問題

''' 解決思路 在一個迷宮節點(x,y)上,可以進行四個方向的探查:maze[x-1][y], maze[x+1][y], maze[x][y-1], maze[x][y+1] 思路:從一個節點開始,任意找下一個能走的點,當找不到能走的點時,退回上一個點尋找是否有其他方向的點。 方法:創建一個空棧,首先將入口位置進棧。當棧不空時循環:獲取棧頂元素,尋找下一個可走的相鄰方塊,如果找不到可走的相鄰方塊,說明當前位置是死胡同,進行回溯(就是講當前位置出棧,看前面的點是否還有別的出路) ''' maze = [ [1,1,1,1,1,1,1,1,1,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,0,0,1,1,0,0,1], [1,0,1,1,1,0,0,0,0,1], [1,0,0,0,1,0,0,0,0,1], [1,0,1,0,0,0,1,0,0,1], [1,0,1,1,1,0,1,1,0,1], [1,1,0,0,0,0,0,1,0,1], [1,1,1,1,1,1,1,1,1,1] ] dirs = [lambda x, y: (x + 1, y), lambda x, y: (x - 1, y), lambda x, y: (x, y - 1), lambda x, y: (x, y + 1)] def mpath(x1, y1, x2, y2): stack = [] stack.append((x1, y1)) while len(stack) > 0: curNode = stack[-1] if curNode[0] == x2 and curNode[1] == y2: #到達終點 for p in stack: print(p) return True for dir in dirs: nextNode = dir(curNode[0], curNode[1]) if maze[nextNode[0]][nextNode[1]] == 0: #找到了下一個 stack.append(nextNode) maze[nextNode[0]][nextNode[1]] = -1 # 標記為已經走過,防止死循環 break else:#四個方向都沒找到 maze[curNode[0]][curNode[1]] = -1 # 死路一條,下次別走了 stack.pop() #回溯 print("沒有路") return False mpath(1,1,8,8)
隊列
- 隊列(Queue)是一個數據集合,僅允許在列表的一端進行插入,另一端進行刪除。
- 進行插入的一端稱為隊尾(rear),插入動作稱為進隊或入隊
- 進行刪除的一端稱為隊頭(front),刪除動作稱為出隊
- 隊列的性質:先進先出(First-in, First-out)
- 雙向隊列:隊列的兩端都允許進行進隊和出隊操作
使用方法:from collections import deque
創建隊列:queue = deque(li)
進隊:append
出隊:popleft
雙向隊列隊首進隊:appendleft
雙向隊列隊尾進隊:pop
隊列的實現原理
隊列的實現原理:環形隊列
隊列的應用:

''' 思路:從一個節點開始,尋找所有下面能繼續走的點。繼續尋找,直到找到出口。 方法:創建一個空隊列,將起點位置進隊。在隊列不為空時循環:出隊一次。如果當前位置為出口,則結束算法;否則找出當前方塊的4個相鄰方塊中可走的方塊,全部進隊。 ''' from collections import deque mg = [ [1,1,1,1,1,1,1,1,1,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,0,0,1,1,0,0,1], [1,0,1,1,1,0,0,0,0,1], [1,0,0,0,1,0,0,0,0,1], [1,0,1,0,0,0,1,0,0,1], [1,0,1,1,1,0,1,1,0,1], [1,1,0,0,0,0,0,1,0,1], [1,1,1,1,1,1,1,1,1,1] ] dirs = [lambda x, y: (x + 1, y), lambda x, y: (x - 1, y), lambda x, y: (x, y - 1), lambda x, y: (x, y + 1)] def print_p(path): curNode = path[-1] realpath = [] print('迷宮路徑為:') while curNode[2] != -1: realpath.append(curNode[0:2]) curNode = path[curNode[2]] realpath.append(curNode[0:2]) realpath.reverse() print(realpath) def mgpath(x1, y1, x2, y2): queue = deque() path = [] queue.append((x1, y1, -1)) mg[x1][y1] = -1 while len(queue) > 0: curNode = queue.popleft() path.append(curNode) if curNode[0] == x2 and curNode[1] == y2: #到達終點 # for i,j,k in path: # print("(%s,%s) %s"%(i,j,k)) print_p(path) return True for dir in dirs: nextNode = dir(curNode[0], curNode[1]) if mg[nextNode[0]][nextNode[1]] == 0: # 找到下一個方塊 queue.append((nextNode[0], nextNode[1], len(path) - 1)) mg[nextNode[0]][nextNode[1]] = -1 # 標記為已經走過 return False mgpath(1,1,8,8)
鏈表
鏈表中每一個元素都是一個對象,每個對象稱為一個節點,包含有數據域key和指向下一個節點的指針next。通過各個節點之間的相互連接,最終串聯成一個鏈表。
節點的定義:
class Node(object): def __init__(self, item): self.item = item self.next = None
頭節點:
鏈表的遍歷:
#遍歷鏈表 def traversal(head): curNode = head #臨時用指針 while cueNode is not None: print(curNode.data) curNode = curNode.Next
鏈表節點的插入和刪除
插入: p.next = curNode.next curNode.next = p 刪除: p = curNode.next curNode.next = curNode.next.next del p
建立鏈表
#頭插法: def createLinkListF(li): l = Node() for num in li: s = Node(num) s.next = l.next l.next = s return l
#尾插法 def createLinkListR(li): l = Node() r = l #r指向尾節點 for num in li: s = Node(num) r.next = s r = s
雙鏈表
雙鏈表中每個節點有兩個指針:一個指向后面節點、一個指向前面節點。
節點定義:
class Node(object): def __init__(self, item=None): self.item = item self.next = None self.prior = None
雙鏈表的插入和刪除
#插入: 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
建立雙鏈表
def createLinkListR(li): l = Node() r = l for num in li: s = Node(num) r.next = s s.prior = r r = s return l, r
棧與隊列的異同
棧(Stack)和隊列(Queue)是兩種操作受限的線性表。
(線性表:線性表是一種線性結構,它是一個含有n≥0個結點的有限序列,同一個線性表中的數據元素數據類型相同並且滿足“一對一”的邏輯關系。
“一對一”的邏輯關系指的是對於其中的結點,有且僅有一個開始結點沒有前驅但有一個后繼結點,有且僅有一個終端結點沒有后繼但有一個前驅結點,其它的結點都有且僅有一個前驅和一個后繼結點。)
這種受限表現在:棧的插入和刪除操作只允許在表的尾端進行(在棧中成為“棧頂”),滿足“FIFO:First In Last Out”;隊列只允許在表尾插入數據元素,在表頭刪除數據元素,滿足“First In First Out”。
棧與隊列的相同點:
1.都是線性結構。
2.插入操作都是限定在表尾進行。
3.都可以通過順序結構和鏈式結構實現。、
4.插入與刪除的時間復雜度都是O(1),在空間復雜度上兩者也一樣。
5.多鏈棧和多鏈隊列的管理模式可以相同。
棧與隊列的不同點:
1.刪除數據元素的位置不同,棧的刪除操作在表尾進行,隊列的刪除操作在表頭進行。
2.應用場景不同;常見棧的應用場景包括括號問題的求解,表達式的轉換和求值,函數調用和遞歸實現,深度優先搜索遍歷等;常見的隊列的應用場景包括計算機系統中各種資源的管理,消息緩沖器的管理和廣度優先搜索遍歷等。
3.順序棧能夠實現多棧空間共享,而順序隊列不能。