称馍#考算法面試題系列:樹的遍歷

首文發(fā)布在 個人博客

兩種通用的遍歷樹的策略

  • DFS(深度優(yōu)先遍歷):先序遍歷弊决,中序遍歷,后序遍歷魁淳;
  • BFS(廣度優(yōu)先遍歷):層序遍歷

深度優(yōu)先遍歷(DFS)

這種方法以深度 depth 優(yōu)先為策略飘诗,從根節(jié)點開始一直遍歷到某個葉子節(jié)點,然后回到根節(jié)點界逛,在遍歷另外一個分支昆稿。

根據(jù)根節(jié)點,左孩子節(jié)點和右孩子節(jié)點的訪問順序又可以將 DFS 細(xì)分為先序遍歷 preorder息拜,中序遍歷 inorder 和后序遍歷 postorder溉潭。

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

按照高度順序,從上往下逐層遍歷節(jié)點少欺。
先遍歷上層節(jié)點再遍歷下層節(jié)點喳瓣。

下圖中按照不同的方法遍歷對應(yīng)子樹,得到的遍歷順序都是 1-2-3-4-5赞别。根據(jù)不同子樹結(jié)構(gòu)比較不同遍歷方法的特點畏陕。

圖片來源leetcode題解

相關(guān)題目(leetcode)

DFS

先序遍歷、中序遍歷仿滔、后序遍歷

  1. 144. 先序遍歷
    先序遍歷為:根節(jié)點 -> 前序遍歷左子樹 -> 前序遍歷右子樹
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var preorderTraversal = function(root) {
    let result = [];
    function pre (root) {
        if(root !== null) {
            // ① 根節(jié)點
            result.push(root.val);
            // ② 前序遍歷左子樹
            pre(root.left);
            // ③ 前序遍歷右子樹
            pre(root.right);
        }
    }
    pre(root);
    return result;
};
  1. 94.中序遍歷

中序遍歷為:中序遍歷左子樹 -> 根結(jié)點 -> 中序遍歷右子樹

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var inorderTraversal = function(root) {
    let result = [];
    function inorder(root) {
        if(root != null) {
            // ① 中序遍歷左子樹
            inorder(root.left);
            // ② 根結(jié)點
            result.push(root.val);
            // ③ 中序遍歷右子樹
            inorder(root.right);
        }
    }
    inorder(root);
    return result;
    
};
  1. 145.后序遍歷
    后序遍歷為:后序遍歷左子樹 -> 后序遍歷右子樹 -> 根結(jié)點
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var postorderTraversal = function(root) {
    const result = [];
    function postorder(root) {
        if(root!== null) {
            // ① 后序遍歷左子樹
            postorder(root.left);
            // ② 后序遍歷右子樹
            postorder(root.right);
            // ③ 根結(jié)點
            result.push(root.val);
        }
    }
    postorder(root);
    return result;
};

根據(jù)兩種遍歷序列構(gòu)造樹

  1. 106.從中序與后序遍歷序列構(gòu)造二叉樹
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {number[]} inorder
 * @param {number[]} postorder
 * @return {TreeNode}
 */
var buildTree = function (inorder, postorder) {
    if (!inorder || inorder.length == 0) {
        return null;
    }
    // 后序遍歷的最后一個節(jié)點一定是根節(jié)點
    let treeNode = new TreeNode(postorder[postorder.length - 1]);
    // 在中序遍歷中找到 根節(jié)點的位置
    let i = inorder.indexOf(postorder[postorder.length - 1]);
    // 根據(jù)左子樹的中序和后序遍歷構(gòu)建左子樹
    treeNode.left = buildTree(inorder.slice(0, i), postorder.slice(0, i));
    // 根據(jù)右子樹的中序和后序遍歷構(gòu)建右子樹
    treeNode.right = buildTree(inorder.slice(i + 1), postorder.slice(i, postorder.length - 1));
    return treeNode;
};
  1. 105. 從前序與中序遍歷序列構(gòu)造二叉樹
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {number[]} preorder
 * @param {number[]} inorder
 * @return {TreeNode}
 */
var buildTree = function(preorder, inorder) {
    if (!inorder || inorder.length == 0) {
        return null;
    }
    // 前序遍歷的第一個節(jié)點一定是根節(jié)點
    let treeNode = new TreeNode(preorder[0]);
     // 在中序遍歷中找到 根節(jié)點的位置
    let i = inorder.indexOf(preorder[0]);
     // 根據(jù)左子樹的前序和中序遍歷構(gòu)建左子樹
    treeNode.left = buildTree(preorder.slice(1, i + 1), inorder.slice(0, i));
     // 根據(jù)右子樹的前序和中序遍歷構(gòu)建右子樹
    treeNode.right = buildTree(preorder.slice(i + 1), inorder.slice(i + 1));
    return treeNode;
};
  1. 889. 根據(jù)前序和后序遍歷構(gòu)造二叉樹
const constructFromPrePost = (pre, post) => {
    const { length } = pre;
    if (length === 0) return null;
    // 前序遍歷的第一個節(jié)點一定是根節(jié)點
    const root = new TreeNode(pre[0]);
    // 在后序遍歷中找到 根節(jié)點的位置
    const index = post.indexOf(pre[1]);
     // 根據(jù)左子樹的前序和后序遍歷構(gòu)建左子樹
    root.left = constructFromPrePost(pre.slice(1, index + 2), post.slice(0, index + 1));
    // 根據(jù)右子樹的前序和后序遍歷構(gòu)建右子樹
    root.right = constructFromPrePost(pre.slice(index + 2, length), post.slice(index + 1, length - 1));
  
    return root;
  };

BFS

  1. 102.層序遍歷

按照高度順序惠毁,從上往下逐層遍歷節(jié)點犹芹。
先遍歷上層節(jié)點再遍歷下層節(jié)點。

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrder = function(root) {
    const result = [];
    // level表示當(dāng)前層級
    function levelOrderNode(root, level) {
        if(root!== null) {
            if(result[level]) {
                result[level].push(root.val)
            } else {
                result[level] = [root.val];
            }
            const nextLevel = level + 1;
            levelOrderNode(root.left, nextLevel);
            levelOrderNode(root.right, nextLevel);
        }
    }
    levelOrderNode(root, 0);
    return result; 
};

最后

這次看完應(yīng)該理解了樹的兩種遍歷策略了吧仁讨,如果還不懂羽莺,建議再看一遍,或者自己去看leetcode相關(guān)的官方題解洞豁。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末盐固,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子丈挟,更是在濱河造成了極大的恐慌刁卜,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件曙咽,死亡現(xiàn)場離奇詭異蛔趴,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)例朱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門孝情,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人洒嗤,你說我怎么就攤上這事箫荡。” “怎么了渔隶?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵羔挡,是天一觀的道長。 經(jīng)常有香客問我间唉,道長绞灼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任呈野,我火速辦了婚禮低矮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘被冒。我一直安慰自己军掂,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布姆打。 她就那樣靜靜地躺著,像睡著了一般肠虽。 火紅的嫁衣襯著肌膚如雪幔戏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天税课,我揣著相機(jī)與錄音闲延,去河邊找鬼痊剖。 笑死,一個胖子當(dāng)著我的面吹牛垒玲,可吹牛的內(nèi)容都是我干的陆馁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼合愈,長吁一口氣:“原來是場噩夢啊……” “哼叮贩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起佛析,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤益老,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后寸莫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捺萌,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年膘茎,在試婚紗的時候發(fā)現(xiàn)自己被綠了桃纯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡披坏,死狀恐怖态坦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情刮萌,我是刑警寧澤驮配,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站着茸,受9級特大地震影響壮锻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜涮阔,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一猜绣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧敬特,春花似錦掰邢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至皱炉,卻和暖如春怀估,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工多搀, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留歧蕉,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓康铭,卻偏偏與公主長得像惯退,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子从藤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354