成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript二叉樹及各種遍歷算法詳情

3403771864 / 465人閱讀

  在之前的文章中我們有講過樹的相關(guān)知識(shí),例如,樹的概念、深度優(yōu)先遍歷和廣度優(yōu)先遍歷。這篇文章講述了一個(gè)特殊的樹——二叉樹。

       什么是二叉樹

  二叉樹是每個(gè)節(jié)點(diǎn)最多只能有兩個(gè)子節(jié)點(diǎn)的樹,如下圖所示:

1.png

  一個(gè)二叉樹具有以下幾個(gè)特質(zhì):

  要計(jì)算在每層有多少個(gè)點(diǎn),可以依據(jù)公式2^(i-1)個(gè)(i是樹的第幾層);

  如果這顆二叉樹的深度為k,那二叉樹最多有2^k-1個(gè)節(jié)點(diǎn);

  在一個(gè)非空的二叉樹中,若使用n0表示葉子節(jié)點(diǎn)的個(gè)數(shù),n2是度為2的非葉子節(jié)點(diǎn)的個(gè)數(shù),那么兩者滿足關(guān)系n0 = n2 + 1。

  滿二叉樹

  如果在一個(gè)二叉樹中,除了葉子節(jié)點(diǎn),其余的節(jié)點(diǎn)的每個(gè)度都是2,則說明該二叉樹是一個(gè)滿二叉樹,

  如下圖所示:

2.png

  滿二叉樹除了滿足普通二叉樹特質(zhì),還具有如下幾個(gè)特質(zhì):

  每個(gè)層節(jié)點(diǎn)公式2^(n-1)(n為層數(shù));

  深度為k的滿二叉樹一定存在2^k-1個(gè)節(jié)點(diǎn),葉子節(jié)點(diǎn)的個(gè)數(shù)為2^(k-1);

  具有n個(gè)節(jié)點(diǎn)的滿二叉樹的深度為log_2^(n+1)。

  完全二叉樹

  如果一個(gè)二叉樹去掉最后一次層是滿二叉樹,且最后一次的節(jié)點(diǎn)是依次從左到右分布的,則這個(gè)二叉樹是一個(gè)完全二叉樹,

  如下圖所示:

3.png

  二叉樹的存儲(chǔ)

  存儲(chǔ)二叉樹的常見方式分為兩種,一種是使用數(shù)組存儲(chǔ),另一種使用鏈表存儲(chǔ)。

  數(shù)組存儲(chǔ)

  使用數(shù)組存儲(chǔ)二叉樹,如果遇到完全二叉樹,存儲(chǔ)順序從上到下,從左到右,如下圖所示:

4.png

  如果是一個(gè)非完全二叉樹,如下圖所示:

5.png

  需要先將其轉(zhuǎn)換為完全二叉樹,然后在進(jìn)行存儲(chǔ),如下圖所示:

6.png

  可以很明顯的看到存儲(chǔ)空間的浪費(fèi)。

  鏈表存儲(chǔ)

  使用鏈表存儲(chǔ)通常將二叉樹中的分為3個(gè)部分,如下圖:

7.png

  這三個(gè)部分依次是左子樹的引用,該節(jié)點(diǎn)包含的數(shù)據(jù),右子樹的引用,存儲(chǔ)方式如下圖所示:

8.png

  與二叉樹相關(guān)的算法

  以下算法中遍歷用到的樹如下

  // tree.js
  const bt = {
  val: 'A',
  left: {
  val: 'B',
  left: { val: 'D', left: null, right: null },
  right: { val: 'E', left: null, right: null },
  },
  right: {
  val: 'C',
  left: {
  val: 'F',
  left: { val: 'H', left: null, right: null },
  right: { val: 'I', left: null, right: null },
  },
  right: { val: 'G', left: null, right: null },
  },
  }
  module.exports = bt

  深度優(yōu)先遍歷

  二叉樹的深度優(yōu)先遍歷與樹的深度優(yōu)先遍歷思路一致,思路如下:

  訪問根節(jié)點(diǎn);

  訪問根節(jié)點(diǎn)的left

  訪問根節(jié)點(diǎn)的right

  重復(fù)執(zhí)行第二三步

  實(shí)現(xiàn)代碼如下:

  const bt = {
  val: 'A',
  left: {
  val: 'B',
  left: { val: 'D', left: null, right: null },
  right: { val: 'E', left: null, right: null },
  },
  right: {
  val: 'C',
  left: {
  val: 'F',
  left: { val: 'H', left: null, right: null },
  right: { val: 'I', left: null, right: null },
  },
  right: { val: 'G', left: null, right: null },
  },
  }
  function dfs(root) {
  if (!root) return
  console.log(root.val)
  root.left && dfs(root.left)
  root.right && dfs(root.right)
  }
  dfs(bt)
  /** 結(jié)果
  A B D E C F H I G
  */

  廣度優(yōu)先遍歷

  實(shí)現(xiàn)思路如下:

  創(chuàng)建隊(duì)列,把根節(jié)點(diǎn)入隊(duì)

  把對(duì)頭出隊(duì)并訪問

  把隊(duì)頭的left和right依次入隊(duì)

  重復(fù)執(zhí)行2、3步,直到隊(duì)列為空

  實(shí)現(xiàn)代碼如下:

  function bfs(root) {
  if (!root) return
  const queue = [root]
  while (queue.length) {
  const node = queue.shift()
  console.log(node.val)
  node.left && queue.push(node.left)
  node.right && queue.push(node.right)
  }
  }
  bfs(bt)
  /** 結(jié)果
  A B C D E F G H I
  */

  先序遍歷

  二叉樹的先序遍歷實(shí)現(xiàn)思想如下:

  訪問根節(jié)點(diǎn);

  對(duì)當(dāng)前節(jié)點(diǎn)的左子樹進(jìn)行先序遍歷;

  對(duì)當(dāng)前節(jié)點(diǎn)的右子樹進(jìn)行先序遍歷;

  如下圖所示:

9.png

  遞歸方式實(shí)現(xiàn)如下:

  const bt = require('./tree')
  function preorder(root) {
  if (!root) return
  console.log(root.val)
  preorder(root.left)
  preorder(root.right)
  }
  preorder(bt)
  /** 結(jié)果
  A B D E C F H I G
  */

  迭代方式實(shí)現(xiàn)如下:

  // 非遞歸版
  function preorder(root) {
  if (!root) return
  // 定義一個(gè)棧,用于存儲(chǔ)數(shù)據(jù)
  const stack = [root]
  while (stack.length) {
  const node = stack.pop()
  console.log(node.val)
  /* 由于棧存在先入后出的特性,所以需要先入右子樹才能保證先出左子樹 */
  node.right && stack.push(node.right)
  node.left && stack.push(node.left)
  }
  }
  preorder(bt)
  /** 結(jié)果
  A B D E C F H I G
  */

  中序遍歷

  二叉樹的中序遍歷實(shí)現(xiàn)思想如下:

  對(duì)當(dāng)前節(jié)點(diǎn)的左子樹進(jìn)行中序遍歷;

  訪問根節(jié)點(diǎn);

  對(duì)當(dāng)前節(jié)點(diǎn)的右子樹進(jìn)行中序遍歷;

  如下圖所示:

10.png

  遞歸方式實(shí)現(xiàn)如下:

  const bt = require('./tree')
  // 遞歸版
  function inorder(root) {
  if (!root) return
  inorder(root.left)
  console.log(root.val)
  inorder(root.right)
  }
  inorder(bt)
  /** 結(jié)果
  D B E A H F I C G
  */

  迭代方式實(shí)現(xiàn)如下:

  // 非遞歸版
  function inorder(root) {
  if (!root) return
  const stack = []
  // 定義一個(gè)指針
  let p = root
  // 如果棧中有數(shù)據(jù)或者p不是null,則繼續(xù)遍歷
  while (stack.length || p) {
  // 如果p存在則一致將p入棧并移動(dòng)指針
  while (p) {
  // 將 p 入棧,并以移動(dòng)指針
  stack.push(p)
  p = p.left
  }
  const node = stack.pop()
  console.log(node.val)
  p = node.right
  }
  }
  inorder(bt)
  /** 結(jié)果
  D B E A H F I C G
  */

  后序遍歷

  二叉樹的后序遍歷實(shí)現(xiàn)思想如下:

  對(duì)當(dāng)前節(jié)點(diǎn)的左子樹進(jìn)行后序遍歷;

  對(duì)當(dāng)前節(jié)點(diǎn)的右子樹進(jìn)行后序遍歷;

  訪問根節(jié)點(diǎn);

  如下圖所示:

11.png

  遞歸方式實(shí)現(xiàn)如下: 

 const bt = require('./tree')
  // 遞歸版
  function postorder(root) {
  if (!root) return
  postorder(root.left)
  postorder(root.right)
  console.log(root.val)
  }
  postorder(bt)
  /** 結(jié)果
  D E B H I F G C A
  */

  迭代方式實(shí)現(xiàn)如下:

  // 非遞歸版
  function postorder(root) {
  if (!root) return
  const outputStack = []
  const stack = [root]
  while (stack.length) {
  const node = stack.pop()
  outputStack.push(node)
  // 這里先入left需要保證left后出,在stack中后出,就是在outputStack棧中先出
  node.left && stack.push(node.left)
  node.right && stack.push(node.right)
  }
  while (outputStack.length) {
  const node = outputStack.pop()
  console.log(node.val)
  }
  }
  postorder(bt)
  /** 結(jié)果
  D E B H I F G C A
  */

  關(guān)于二叉樹及各種遍歷算法相關(guān)內(nèi)容已講述完畢。


文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/127772.html

相關(guān)文章

  • Java數(shù)據(jù)結(jié)構(gòu)與算法——二叉樹及操作(包括叉樹遍歷)

    摘要:本篇主要介紹二叉樹的概念二叉樹的表示二叉樹的操作三種遍歷方式實(shí)現(xiàn)求二叉樹的子樹求節(jié)點(diǎn)的父節(jié)點(diǎn)二叉樹高度,可能是考試中的,也可能是面試中的。通常二叉樹的遍歷根據(jù)根節(jié)點(diǎn)的遍歷次序分為先根遍歷中根遍歷后根遍歷。 聲明:碼字不易,轉(zhuǎn)載請(qǐng)注明出處,歡迎文章下方討論交流。 前言:Java數(shù)據(jù)結(jié)構(gòu)與算法專題會(huì)不定時(shí)更新,歡迎各位讀者監(jiān)督。本篇主要介紹二叉樹的概念、二叉樹的表示、二叉樹的操作(三種遍歷...

    muddyway 評(píng)論0 收藏0
  • Python數(shù)據(jù)結(jié)構(gòu)——解析樹及樹的遍歷

    摘要:左子樹的加法運(yùn)算結(jié)果為,右子樹的減法運(yùn)算結(jié)果為。如圖,該圖說明了隨著每個(gè)新的字符被讀入后該解析樹的內(nèi)容和結(jié)構(gòu)。使函數(shù)走向基點(diǎn)的遞歸過程就是調(diào)用求值函數(shù)計(jì)算當(dāng)前節(jié)點(diǎn)的左子樹右子樹的值。最后,我們將在圖中創(chuàng)建的解析樹上遍歷求值。 解析樹 完成樹的實(shí)現(xiàn)之后,現(xiàn)在我們來看一個(gè)例子,告訴你怎么樣利用樹去解決一些實(shí)際問題。在這個(gè)章節(jié),我們來研究解析樹。解析樹常常用于真實(shí)世界的結(jié)構(gòu)表示,例如句子或數(shù)...

    miguel.jiang 評(píng)論0 收藏0
  • 比特幣區(qū)塊結(jié)構(gòu)Merkle樹及簡(jiǎn)單支付驗(yàn)證分析

    摘要:區(qū)塊體則包括當(dāng)前區(qū)塊經(jīng)過驗(yàn)證的區(qū)塊創(chuàng)建過程中生成的所有交易記錄。假如要驗(yàn)證區(qū)塊結(jié)構(gòu)圖中交易,節(jié)點(diǎn)會(huì)通過向相鄰節(jié)點(diǎn)索要通過消息包括從交易哈希值沿樹上溯至區(qū)塊頭根哈希處的哈希序列即哈希節(jié)點(diǎn)稱為認(rèn)證路徑來確認(rèn)交易的存在性和正確性。 本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)原文鏈接:比特幣區(qū)塊結(jié)構(gòu)Merkle樹及簡(jiǎn)單支付驗(yàn)證分析原文已更新,請(qǐng)讀者前往原文閱讀 在比特幣網(wǎng)絡(luò)中,不是每個(gè)節(jié)點(diǎn)都有能力儲(chǔ)存完整的...

    zzzmh 評(píng)論0 收藏0
  • Leetcode PHP題解--D76 993. Cousins in Binary Tree

    摘要:題目鏈接題目分析在二叉樹中,若兩個(gè)葉子節(jié)點(diǎn)的層數(shù)相同,但具有不同的父節(jié)點(diǎn),那么這兩個(gè)節(jié)點(diǎn)互為節(jié)點(diǎn)。給定一個(gè)二叉樹及兩個(gè)節(jié)點(diǎn),返回兩個(gè)節(jié)點(diǎn)在二叉樹中,是否互為節(jié)點(diǎn)。遍歷完成后,直接判斷數(shù)組中對(duì)應(yīng)的值是否相同即可。 D76 993. Cousins in Binary Tree 題目鏈接 993. Cousins in Binary Tree 題目分析 在二叉樹中,若兩個(gè)葉子節(jié)點(diǎn)的層數(shù)相同...

    張遷 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<