自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

數(shù)據(jù)結(jié)構(gòu)與算法系列 - 深度優(yōu)先和廣度優(yōu)先

開發(fā) 前端 算法
本篇討論深度優(yōu)先搜索和廣度優(yōu)先搜索相關(guān)內(nèi)容。

前言

數(shù)據(jù)結(jié)構(gòu)與算法系列(完成部分):

  1. 時(shí)間復(fù)雜度和空間復(fù)雜度分析
  2. 數(shù)組的基本實(shí)現(xiàn)和特性
  3. 鏈表和跳表的基本實(shí)現(xiàn)和特性
  4. 棧、隊(duì)列、優(yōu)先隊(duì)列、雙端隊(duì)列的實(shí)現(xiàn)與特性
  5. 哈希表、映射、集合的實(shí)現(xiàn)與特性
  6. 樹、二叉樹、二叉搜索樹的實(shí)現(xiàn)與特性
  7. 堆和二叉堆的實(shí)現(xiàn)和特性
  8. 圖的實(shí)現(xiàn)和特性
  9. 遞歸的實(shí)現(xiàn)、特性以及思維要點(diǎn)
  10. 分治、回溯的實(shí)現(xiàn)和特性
  11. 深度優(yōu)先搜索、廣度優(yōu)先搜索的實(shí)現(xiàn)和特性
  12. 貪心算法的實(shí)現(xiàn)和特性
  13. 二分查找的實(shí)現(xiàn)和特性
  14. 動(dòng)態(tài)規(guī)劃的實(shí)現(xiàn)及關(guān)鍵點(diǎn)
  15. Tire樹的基本實(shí)現(xiàn)和特性
  16. 并查集的基本實(shí)現(xiàn)和特性
  17. 剪枝的實(shí)現(xiàn)和特性
  18. 雙向BFS的實(shí)現(xiàn)和特性
  19. 啟發(fā)式搜索的實(shí)現(xiàn)和特性
  20. AVL樹和紅黑樹的實(shí)現(xiàn)和特性
  21. 位運(yùn)算基礎(chǔ)與實(shí)戰(zhàn)要點(diǎn)
  22. 布隆過濾器的實(shí)現(xiàn)及應(yīng)用
  23. LRU Cache的實(shí)現(xiàn)及應(yīng)用
  24. 初級(jí)排序和高級(jí)排序的實(shí)現(xiàn)和特性
  25. 字符串算法

PS:大部分已經(jīng)完成在公眾號(hào)或者GitHub上,后面陸續(xù)會(huì)在頭條補(bǔ)充鏈接(不允許有外部鏈接)

本篇討論深度優(yōu)先搜索和廣度優(yōu)先搜索相關(guān)內(nèi)容。

關(guān)于搜索&遍歷

對(duì)于搜索來說,我們絕大多數(shù)情況下處理的都是叫 “所謂的暴力搜索” ,或者是說比較簡單樸素的搜索,也就是說你在搜索的時(shí)候沒有任何所謂的智能的情況在里面考慮,很多情況下它做的一件事情就是把所有的結(jié)點(diǎn)全部遍歷一次,然后找到你要的結(jié)果。

基于這樣的一個(gè)數(shù)據(jù)結(jié)構(gòu),如果這個(gè)數(shù)據(jù)結(jié)構(gòu)本身是沒有任何特點(diǎn)的,也就是說是一個(gè)很普通的樹或者很普通的圖。那么我們要做的一件事情就是遍歷所有的結(jié)點(diǎn)。同時(shí)保證每個(gè)點(diǎn)訪問一次且僅訪問一次,最后找到結(jié)果。

那么我們先把搜索整個(gè)先化簡情況,我們就收縮到在樹的這種情況下來進(jìn)行搜索。

如果我們要找到我們需要的一個(gè)值,在這個(gè)樹里面我們要怎么做?那么毫無疑問就是從根這邊開始先搜左子樹,然后再往下一個(gè)一個(gè)一個(gè)一個(gè)點(diǎn)走過去,然后走完來之后再走右子樹,直到找到我們的點(diǎn),這就是我們所采用的方式。

 

再回到我們數(shù)據(jù)結(jié)構(gòu)定義,它只有左子樹和右子樹。

我們要實(shí)現(xiàn)這樣一個(gè)遍歷或者搜索的話,毫無疑問我們要保證的事情就是

  • 每個(gè)結(jié)點(diǎn)都要訪問一次
  • 每個(gè)結(jié)點(diǎn)僅僅要訪問一次
  • 對(duì)于結(jié)點(diǎn)訪問的順序不限
  • 深度優(yōu)先:Depth First Search
  • 廣度優(yōu)先:Breadth First Search

僅訪問一次的意思就是代表我們?cè)谒阉髦校覀儾幌胱鲞^多無用的訪問,不然的話我們的訪問的效率會(huì)非常的慢。

當(dāng)然的話還可以有其余的搜索,其余的搜索的話就不再是深度優(yōu)先或者廣度優(yōu)先了,而是按照優(yōu)先級(jí)優(yōu)先 。當(dāng)然你也可以隨意定義,比如說從中間優(yōu)先類似于其他的東西,但只不過的話你定義的話要有現(xiàn)實(shí)中的場(chǎng)景。所以你可以認(rèn)為是一般來說就是深度優(yōu)先、廣度優(yōu)先,另外的話就是優(yōu)先級(jí)優(yōu)先。按照優(yōu)先級(jí)優(yōu)先搜索的話,其實(shí)更加適用于現(xiàn)實(shí)中的很多業(yè)務(wù)場(chǎng)景,而這樣的算法我們一般把它稱為啟發(fā)式搜索,更多應(yīng)用在深度學(xué)習(xí)領(lǐng)域。而這種比如說優(yōu)先級(jí)優(yōu)先的話,在很多時(shí)候現(xiàn)在已經(jīng)應(yīng)用在各種推薦算法和高級(jí)的搜索算法,讓你搜出你中間最感興趣的內(nèi)容,以及每天打開抖音、快手的話就給你推薦你最感興趣的內(nèi)容,其實(shí)就是這個(gè)原因。

深度優(yōu)先搜索(DFS)

遞歸寫法

遞歸的寫法,一開始就是遞歸的終止條件,然后處理當(dāng)前的層,然后再下轉(zhuǎn)。

  • 那么處理當(dāng)前層的話就是相當(dāng)于訪問了結(jié)點(diǎn) node,然后把這個(gè)結(jié)點(diǎn) node 加到已訪問的結(jié)點(diǎn)里面去;
  • 那么終止條件的話,就是如果這個(gè)結(jié)點(diǎn)之前已經(jīng)訪問過了,那就不管了;
  • 那么下轉(zhuǎn)的話,就是走到它的子結(jié)點(diǎn),二叉樹來說的話就是左孩子和右孩子,如果是圖的話就是連同的相鄰結(jié)點(diǎn),如果是多叉樹的話這里就是一個(gè)children,然后把所有的children的話遍歷一次。

1.二叉樹模版

 

Java 版本

  1. //C/C++ 
  2. //遞歸寫法: 
  3. map<intint> visited; 
  4.  
  5. void dfs(Node* root) { 
  6.   // terminator 
  7.   if (!root) return ; 
  8.  
  9.   if (visited.count(root->val)) { 
  10.     // already visited 
  11.     return ; 
  12.   } 
  13.  
  14.   visited[root->val] = 1; 
  15.  
  16.   // process current node here.  
  17.   // ... 
  18.   for (int i = 0; i < root->children.size(); ++i) { 
  19.     dfs(root->children[i]); 
  20.   } 
  21.   return ; 

Python 版本

  1. #Python 
  2. visited = set()  
  3.  
  4. def dfs(node, visited): 
  5.     if node in visited: # terminator 
  6.         # already visited  
  7.         return  
  8.  
  9.     visited.add(node)  
  10.  
  11.     # process current node here.  
  12.     ... 
  13.     for next_node in node.children():  
  14.         if next_node not in visited:  
  15.             dfs(next_node, visited) 

C/C++ 版本

  1. //C/C++ 
  2. //遞歸寫法: 
  3. map<intint> visited; 
  4.  
  5. void dfs(Node* root) { 
  6.   // terminator 
  7.   if (!root) return ; 
  8.  
  9.   if (visited.count(root->val)) { 
  10.     // already visited 
  11.     return ; 
  12.   } 
  13.  
  14.   visited[root->val] = 1; 
  15.  
  16.   // process current node here.  
  17.   // ... 
  18.   for (int i = 0; i < root->children.size(); ++i) { 
  19.     dfs(root->children[i]); 
  20.   } 
  21.   return ; 

JavaScript版本

  1. visited = set()  
  2. def dfs(node, visited): 
  3.     if node in visited: # terminator 
  4.         # already visited  
  5.         return  
  6.     visited.add(node)  
  7.     # process current node here.  
  8.     ... 
  9.     for next_node in node.children():  
  10.       if next_node not in visited:  
  11.         dfs(next_node, visited) 

2.多叉樹模版

  1. visited = set()  
  2. def dfs(node, visited): 
  3.     if node in visited: # terminator 
  4.         # already visited  
  5.         return  
  6.     visited.add(node)  
  7.     # process current node here.  
  8.     ... 
  9.     for next_node in node.children():  
  10.       if next_node not in visited:  
  11.         dfs(next_node, visited) 

非遞歸寫法

Python版本

  1. #Python 
  2. def DFS(self, tree):  
  3.  
  4.     if tree.root is None:  
  5.         return []  
  6.  
  7.     visited, stack = [], [tree.root] 
  8.  
  9.     while stack:  
  10.         node = stack.pop()  
  11.         visited.add(node) 
  12.  
  13.         process (node)  
  14.         nodes = generate_related_nodes(node)  
  15.         stack.push(nodes)  
  16.  
  17.     # other processing work  
  18.     ... 

C/C++版本

  1. //C/C++ 
  2. //非遞歸寫法: 
  3. void dfs(Node* root) { 
  4.   map<intint> visited; 
  5.   if(!root) return ; 
  6.  
  7.   stack<Node*> stackNode; 
  8.   stackNode.push(root); 
  9.  
  10.   while (!stackNode.empty()) { 
  11.     Node* node = stackNode.top(); 
  12.     stackNode.pop(); 
  13.     if (visited.count(node->val)) continue
  14.     visited[node->val] = 1; 
  15.  
  16.  
  17.     for (int i = node->children.size() - 1; i >= 0; --i) { 
  18.         stackNode.push(node->children[i]); 
  19.     } 
  20.   } 
  21.  
  22.   return ; 

遍歷順序

我們看深度優(yōu)先搜索或者深度優(yōu)先遍歷的話,它的整個(gè)遍歷順序毫無疑問根節(jié)點(diǎn) 1 永遠(yuǎn)最先開始的,接下來往那個(gè)分支走其實(shí)都一樣的,我們簡單起見就是從最左邊開始走,那么它深度優(yōu)先的話就會(huì)走到底。

參考多叉樹模版我們可以在腦子里面或者畫一個(gè)圖把它遞歸起來的話,把遞歸的狀態(tài)樹畫出來,就是這么一個(gè)結(jié)構(gòu)。

 

  • 就比如說它開始剛進(jìn)來的話,傳的是 root 的話,root 就會(huì)先放到 visited 里面,表示 root 已經(jīng)被 visit,被 visited之后就從 root.childern里面找 next_node,所有它的next_node都沒有被訪問過的,所以它就會(huì)先訪問最左邊的這個(gè)結(jié)點(diǎn),這里注意當(dāng)它最左邊這個(gè)結(jié)點(diǎn)先拿出來了,判斷沒有在 visited里面,因?yàn)槌?root之外其他結(jié)點(diǎn)都沒有被 visited過,那么沒有的話它就直接調(diào)dfs,next_node 就是把最左邊結(jié)點(diǎn)放進(jìn)去,再把 visited也一起放進(jìn)去。
  • 遞歸調(diào)用的一個(gè)特殊,它不會(huì)等這個(gè)循環(huán)跑完,它就直接推進(jìn)到下一層了,也就是當(dāng)前夢(mèng)境的話這里寫了一層循環(huán),但是在第一層循環(huán)的時(shí)候,我就要開始下鉆到新的一層夢(mèng)境里面去了。

圖的遍歷順序

廣度優(yōu)先搜索(BFS)

廣度優(yōu)先遍歷它就不再是用遞歸也不再是用棧了,而是用所謂的隊(duì)列。你可以把它想象成一個(gè)水滴,滴到1這個(gè)位置,然后它的水波紋一層一層一層擴(kuò)散出去就行了。

兩者對(duì)比

BFS代碼模板

  1. //Java 
  2. public class TreeNode { 
  3.     int val; 
  4.     TreeNode left
  5.     TreeNode right
  6.  
  7.     TreeNode(int x) { 
  8.         val = x; 
  9.     } 
  10.  
  11. public List<List<Integer>> levelOrder(TreeNode root) { 
  12.     List<List<Integer>> allResults = new ArrayList<>(); 
  13.     if (root == null) { 
  14.         return allResults; 
  15.     } 
  16.     Queue<TreeNode> nodes = new LinkedList<>(); 
  17.     nodes.add(root); 
  18.     while (!nodes.isEmpty()) { 
  19.         int size = nodes.size(); 
  20.         List<Integer> results = new ArrayList<>(); 
  21.         for (int i = 0; i < size; i++) { 
  22.             TreeNode node = nodes.poll(); 
  23.             results.add(node.val); 
  24.             if (node.left != null) { 
  25.                 nodes.add(node.left); 
  26.             } 
  27.             if (node.right != null) { 
  28.                 nodes.add(node.right); 
  29.             } 
  30.         } 
  31.         allResults.add(results); 
  32.     } 
  33.     return allResults; 

  1. # Python 
  2. def BFS(graph, start, end): 
  3.     visited = set() 
  4.     queue = []  
  5.     queue.append([start])  
  6.     while queue:  
  7.         node = queue.pop()  
  8.         visited.add(node) 
  9.         process(node)  
  10.         nodes = generate_related_nodes(node)  
  11.         queue.push(nodes) 
  12.     # other processing work  
  13.     ... 

  1. // C/C++ 
  2. void bfs(Node* root) { 
  3.   map<intint> visited; 
  4.   if(!root) return ; 
  5.  
  6.   queue<Node*> queueNode; 
  7.   queueNode.push(root); 
  8.  
  9.   while (!queueNode.empty()) { 
  10.     Node* node = queueNode.top(); 
  11.     queueNode.pop(); 
  12.     if (visited.count(node->val)) continue
  13.     visited[node->val] = 1; 
  14.  
  15.     for (int i = 0; i < node->children.size(); ++i) { 
  16.         queueNode.push(node->children[i]); 
  17.     } 
  18.   } 
  19.  
  20.   return ; 

  1. //JavaScript 
  2. const bfs = (root) => { 
  3.   let result = [], queue = [root] 
  4.   while (queue.length > 0) { 
  5.     let level = [], n = queue.length 
  6.     for (let i = 0; i < n; i++) { 
  7.       let node = queue.pop() 
  8.       level.push(node.val)  
  9.       if (node.left) queue.unshift(node.left
  10.       if (node.right) queue.unshift(node.right
  11.     } 
  12.     result.push(level
  13.   } 
  14.   return result 
  15. }; 

 

 

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2021-04-28 07:59:21

深度優(yōu)先搜索

2023-04-14 08:07:20

數(shù)據(jù)結(jié)構(gòu)算法搜索

2025-02-26 05:00:00

DFS算法遞歸

2020-04-16 13:48:27

DFS BFS優(yōu)先遍歷

2021-06-11 06:10:09

Python數(shù)據(jù)結(jié)構(gòu)算法

2021-04-19 09:08:19

無向圖數(shù)據(jù)結(jié)構(gòu)

2023-11-06 07:46:22

圖算法數(shù)據(jù)結(jié)構(gòu)

2020-10-21 14:57:04

數(shù)據(jù)結(jié)構(gòu)算法圖形

2023-03-08 08:03:09

數(shù)據(jù)結(jié)構(gòu)算法歸并排序

2023-10-27 07:04:20

2019-03-29 09:40:38

數(shù)據(jù)結(jié)構(gòu)算法前端

2017-03-20 13:09:33

Swift廣度優(yōu)先搜索手游開發(fā)

2023-03-02 08:15:13

2023-03-10 08:07:39

數(shù)據(jù)結(jié)構(gòu)算法計(jì)數(shù)排序

2023-03-07 08:02:07

數(shù)據(jù)結(jié)構(gòu)算法數(shù)列

2020-08-12 08:30:20

數(shù)據(jù)結(jié)構(gòu)算法

2015-08-24 15:06:13

大數(shù)據(jù)

2023-04-27 09:13:20

排序算法數(shù)據(jù)結(jié)構(gòu)

2023-03-13 10:08:31

數(shù)據(jù)結(jié)構(gòu)算法

2023-11-06 06:43:23

單鏈表查詢數(shù)據(jù)結(jié)構(gòu)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)