廣度優(yōu)先遍歷(BFS)


廣度優(yōu)先遍歷呈現(xiàn)出「一層一層向外擴(kuò)張」的特點(diǎn)啡专,先看到的結(jié)點(diǎn)先遍歷险毁,后看到的結(jié)點(diǎn)后遍歷,因此「廣度優(yōu)先遍歷」可以借助「隊(duì)列」實(shí)現(xiàn)畔况。

我們以二叉樹來舉例鲸鹦,從根節(jié)點(diǎn)開始,我們將根節(jié)點(diǎn)放入一個(gè)列隊(duì)跷跪,然后開始遍歷列隊(duì)里面的節(jié)點(diǎn)馋嗜,把列隊(duì)中遍歷到的節(jié)點(diǎn)可達(dá)節(jié)點(diǎn)從左往右的順序紛紛放入到列隊(duì),當(dāng)遍歷完某一層節(jié)點(diǎn)個(gè)數(shù)的時(shí)候吵瞻,列隊(duì)里面所剩下的節(jié)點(diǎn)就是下一層的節(jié)點(diǎn)葛菇,如此循環(huán)甘磨,直到遍歷完所有節(jié)點(diǎn)或者達(dá)到目標(biāo)節(jié)點(diǎn)
此時(shí)便是到達(dá)目標(biāo)節(jié)點(diǎn)最少深度眯停。

下面用一個(gè)題目來舉例:

我們有一個(gè)二叉樹济舆,需要根據(jù)下面的遍歷結(jié)果輸出:

    3
   / \
  9  20
    /  \
   15   7
//節(jié)點(diǎn)的結(jié)構(gòu)如下
//給定一個(gè)樹節(jié)點(diǎn)結(jié)構(gòu)
public class TreeNode {
      int val;
      TreeNode left;
      TreeNode right;
      TreeNode() {}
      TreeNode(int val) { this.val = val; }
      TreeNode(int val, TreeNode left, TreeNode right) {
          this.val = val;
          this.left = left;
          this.right = right;
      }
}

需要返回的結(jié)果結(jié)構(gòu)為:

[
  [3],
  [9,20],
  [15,7]
]

思路

  • 題目要求我們一層一層輸出樹的結(jié)點(diǎn)的值,很明顯需要使用「廣度優(yōu)先遍歷」實(shí)現(xiàn)莺债;
  • 廣度優(yōu)先遍歷借助「隊(duì)列」實(shí)現(xiàn)滋觉;
  • 注意子結(jié)點(diǎn)入隊(duì)的時(shí)候,非空的判斷很重要:在隊(duì)列的隊(duì)首元素出隊(duì)的時(shí)候齐邦,>一定要在左(右)子結(jié)點(diǎn)非空的時(shí)候才將左(右)子結(jié)點(diǎn)入隊(duì)椎侠。
  • 樹的廣度優(yōu)先遍歷的寫法模式相對(duì)固定:
    • 使用隊(duì)列;
    • 在隊(duì)列非空的時(shí)候措拇,動(dòng)態(tài)取出隊(duì)首元素我纪;
    • 取出隊(duì)首元素的時(shí)候,把隊(duì)首元素相鄰的結(jié)點(diǎn)(非空)加入隊(duì)列儡羔。
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class Solution {

    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) {
            return res;
        }

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            // 注意 1:一定要先把當(dāng)前隊(duì)列的結(jié)點(diǎn)總數(shù)暫存起來
            int currentSize = queue.size();
          //下面這個(gè)循環(huán)主要用于分層,如果不需要分層汰蜘,則可以不使用這個(gè)循環(huán)
            List<Integer> currentLevel = new ArrayList<>();
            for (int i = 0; i < currentSize; i++) {
                TreeNode front = queue.poll();
                currentLevel.add(front.val);
                // 注意 2:左(右)孩子結(jié)點(diǎn)非空才加入隊(duì)列
                if (front.left != null) {
                    queue.offer(front.left);
                }
                if (front.right != null) {
                    queue.offer(front.right);
                }
            }
            res.add(currentLevel);
        }
        return res;
    }
}

使用廣度優(yōu)先遍歷得到無權(quán)圖的最短路徑

上面舉的例子是一個(gè)二叉樹仇冯,不存在環(huán)苛坚,例如迷宮,是存在交叉口的這種情況需要特別注意:將結(jié)點(diǎn)添加到隊(duì)列以后色难,一定要馬上標(biāo)記為「已經(jīng)訪問」泼舱,否則相同結(jié)點(diǎn)會(huì)重復(fù)入隊(duì),這一點(diǎn)在初學(xué)的時(shí)候很容易忽略枷莉。

另外一點(diǎn)還需要強(qiáng)調(diào)娇昙,廣度優(yōu)先遍歷用于求解「無權(quán)圖」的最短路徑,因此一定要認(rèn)清「無權(quán)圖」這個(gè)前提條件笤妙。如果是帶權(quán)圖冒掌,就需要使用相應(yīng)的專門的算法去解決它們。事實(shí)上蹲盘,這些「專門」的算法的思想也都基于「廣度優(yōu)先遍歷」的思想股毫,我們?yōu)榇蠹依e如下:

  • 帶權(quán)有向圖、且所有權(quán)重都非負(fù)的單源最短路徑問題:使用Dijkstra 算法召衔;
  • 帶權(quán)有向圖的單源最短路徑問題:Bellman-Ford算法铃诬;
  • 一個(gè)圖的所有結(jié)點(diǎn)對(duì)的最短路徑問題:Floy-Warshall算法。

總結(jié)

廣度優(yōu)先遍歷可以用于「樹」「圖」的問題的遍歷;
廣度優(yōu)先遍歷作用于「無權(quán)圖」趣席,得到的是「最短路徑」兵志。如果題目有讓求「最小」「最短」宣肚、「最少」毒姨,可以考慮這個(gè)問題是不是可以建立成一個(gè)「圖形結(jié)構(gòu)」或者「樹形結(jié)構(gòu)」,用「廣度優(yōu)先遍歷」的思想求得「最小」「最短」「最少」的數(shù)值梆靖;
廣度優(yōu)先遍歷作用于圖論問題的時(shí)候,結(jié)點(diǎn)在加入隊(duì)列以后標(biāo)記為已經(jīng)訪問俘枫,否則會(huì)出現(xiàn)結(jié)點(diǎn)重復(fù)入隊(duì)的情況。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末逮走,一起剝皮案震驚了整個(gè)濱河市鸠蚪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌师溅,老刑警劉巖茅信,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異墓臭,居然都是意外死亡蘸鲸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門窿锉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酌摇,“玉大人,你說我怎么就攤上這事嗡载∫ざ啵” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵洼滚,是天一觀的道長(zhǎng)埂息。 經(jīng)常有香客問我,道長(zhǎng)遥巴,這世上最難降的妖魔是什么千康? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮挪哄,結(jié)果婚禮上吧秕,老公的妹妹穿的比我還像新娘琉闪。我一直安慰自己迹炼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著斯入,像睡著了一般砂碉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上刻两,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天增蹭,我揣著相機(jī)與錄音,去河邊找鬼磅摹。 笑死滋迈,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的户誓。 我是一名探鬼主播饼灿,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼帝美!你這毒婦竟也來了碍彭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤悼潭,失蹤者是張志新(化名)和其女友劉穎庇忌,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舰褪,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡皆疹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了占拍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片墙基。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖刷喜,靈堂內(nèi)的尸體忽然破棺而出残制,到底是詐尸還是另有隱情,我是刑警寧澤掖疮,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布初茶,位于F島的核電站,受9級(jí)特大地震影響浊闪,放射性物質(zhì)發(fā)生泄漏恼布。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一搁宾、第九天 我趴在偏房一處隱蔽的房頂上張望折汞。 院中可真熱鬧,春花似錦盖腿、人聲如沸爽待。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鸟款。三九已至膏燃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間何什,已是汗流浹背组哩。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留处渣,地道東北人伶贰。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像罐栈,于是被迫代替她去往敵國(guó)和親幕袱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容