回溯法
回溯法(探索與回溯法)是一種選優搜索法,按選優條件向前搜索,以達到目標。
但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,
這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為“回溯點”。
1.深度優先搜索(DepthFirstSearch)
深度優先搜索的主要特征就是,假設一個頂點有不少相鄰頂點,當我們搜索到該頂點,我們對於它的相鄰頂點並不是現在就對所有都進行搜索,
而是對一個頂點繼續往后搜索,直到某個頂點,他周圍的相鄰頂點都已經被訪問過了,這時他就可以返回,對它來的那個頂點的其余頂點進行搜索。
深度優先搜索的實現可以利用遞歸很簡單地實現。
2.廣度優先搜索(BreadthFirstSearch)
廣度優先搜索相對於深度優先搜索側重點不一樣,
深度優先好比是一個人走迷宮,一次只能選定一條路走下去,
而廣度優先搜索好比是一次能夠有任意多個人,一次就走到和一個頂點相連的所有未訪問過的頂點,然后再從這些頂點出發,繼續這個過程。
具體實現的時候我們使用先進先出隊列來實現這個過程:
-
首先將起點加入隊列,然后將其出隊,把和起點相連的頂點加入隊列,
-
將隊首元素v出隊並標記他
-
將和v相連的未標記的元素加入隊列,然后繼續執行步驟2直到隊列為空
廣度優先搜索的一個重要作用就是它能夠找出最短路徑,這個很好理解,因為廣度優先搜索相當於每次從一個起點開始向所有可能的方向走一步,那么第一次到達目的地的這個路徑一定是最短的,而到達了之后由於這個點已經被訪問過而不會再被訪問,這個路徑就不會被更改了。
廣度優先遍歷是爬蟲中使用最廣泛的一種爬蟲策略,之所以使用廣度優先搜索策略,主要原因有三點:
- 重要的網頁往往離種子比較近,例如我們打開新聞網站的時候往往是最熱門的新聞,隨着不斷的深入沖浪,所看到的網頁的重要性越來越低。
- 萬維網的實際深度最多能達到17層,但到達某個網頁總存在一條很短的路徑。而廣度優先遍歷會以最快的速度到達這個網頁。
- 廣度優先有利於多爬蟲的合作抓取,多爬蟲合作通常先抓取站內鏈接,抓取的封閉性很強。
遍歷二叉樹圖形
# 深度優先: 根左右 遍歷 # 廣度優先: 層次遍歷,一層一層遍歷 # 深度優先: 根左右 遍歷 (遞歸實現) def depth_tree(tree_node): if tree_node is not None: print(tree_node._data) if tree_node._left is not None: return depth_tree(tree_node._left) # 遞歸遍歷 if tree_node._right is not None: return depth_tree(tree_node._right) # 遞歸遍歷 # 廣度優先: 層次遍歷,一層一層遍歷(隊列實現) def level_queue(root): if root is None: return my_queue = [] node = root my_queue.append(node) # 根結點入隊列 while my_queue: node = my_queue.pop(0) # 出隊列 print(node.elem) # 訪問結點 if node.lchild is not None: my_queue.append(node.lchild) # 入隊列 if node.rchild is not None: my_queue.append(node.rchild) # 入隊列
數據結構設計:
列表法:
# 樹的數據結構設計 # 1.列表法 # 簡述:列表里包含三個元素:根結點、左結點、右結點 my_Tree = [ 'D', # 根結點 ['B', ['F',[],[]], ['G',['E',[],[]],[]] ], # 左子樹 ['C', [], ['A',['H',[],[]],[]] ] # 右子樹 ] # 列表操作函數 # pop() 函數用於移除列表中的一個元素(默認最后一個元素),並且返回該元素的值。 # insert() 函數用於將指定對象插入列表的指定位置,沒有返回值。 # 深度優先: 根左右 遍歷 (遞歸實現) def depth_tree(tree_node): if tree_node: print(tree_node[0]) # 訪問左子樹 if tree_node[1]: depth_tree(tree_node[1]) # 遞歸遍歷 # 訪問右子樹 if tree_node[2]: depth_tree(tree_node[2]) # 遞歸遍歷 depth_tree(my_Tree) # result: # D B F G E C A H # 廣度優先: 層次遍歷,一層一層遍歷(隊列實現) def level_queue(root): if not root: return my_queue = [] node = root my_queue.append(node) # 根結點入隊列 while my_queue: node = my_queue.pop(0) # 出隊列 print(node[0]) # 訪問結點 if node[1]: my_queue.append(node[1]) # 入隊列 if node[2]: my_queue.append(node[2]) # 入隊列 level_queue(my_Tree) # result : # D B C F G A E H
方法二:構造類節點法
#2.構造類 # Tree類,類變量root 為根結點,為str類型 # 類變量right/left 為左右節點,為Tree型,默認為空 class Tree: root = '' right = None left = None # 初始化類 def __init__(self,node): self.root = node def set_root(self,node): self.root = node def get_root(self): return self.root # 初始化樹 # 設置所有根結點 a = Tree('A') b = Tree('B') c = Tree('C') d = Tree('D') e = Tree('E') f = Tree('F') g = Tree('G') h = Tree('H') # 設置節點之間聯系,生成樹 a.left = h b.left = f b.right = g c.right = a d.left = b d.right = c g.left = e # 深度優先: 根左右 遍歷 (遞歸實現) def depth_tree(tree_node): if tree_node is not None: print(tree_node.root) if tree_node.left is not None: depth_tree(tree_node.left) # 遞歸遍歷 if tree_node.right is not None: depth_tree(tree_node.right) # 遞歸遍歷 depth_tree(d) # 傳入根節點 # result: # D B F G E C A H # 廣度優先: 層次遍歷,一層一層遍歷(隊列實現) def level_queue(root): if root is None: return my_queue = [] node = root my_queue.append(node) # 根結點入隊列 while my_queue: node = my_queue.pop(0) # 出隊列 print(node.root) # 訪問結點 if node.left is not None: my_queue.append(node.left) # 入隊列 if node.right is not None: my_queue.append(node.right) # 入隊列 level_queue(d) # result : # D B C F G A E H
本文摘抄自公眾號:簡說python,本人一直跟着學習的一個公眾號.