溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript二叉樹及遍歷算法實例分析

發(fā)布時間:2022-07-28 09:40:14 來源:億速云 閱讀:200 作者:iii 欄目:web開發(fā)

這篇“JavaScript二叉樹及遍歷算法實例分析”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“JavaScript二叉樹及遍歷算法實例分析”文章吧。

JavaScript二叉樹及遍歷算法實例分析

什么是二叉樹

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

JavaScript二叉樹及遍歷算法實例分析

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

  • i層的節(jié)點最有只有2^(i-1)個;

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

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

滿二叉樹

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

如下圖所示:

JavaScript二叉樹及遍歷算法實例分析

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

  • 滿二叉樹的的第n層具有2^(n-1)個節(jié)點;

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

  • 具有n個節(jié)點的滿二叉樹的深度為log_2^(n+1)

完全二叉樹

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

如下圖所示:

JavaScript二叉樹及遍歷算法實例分析

二叉樹的存儲

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

數(shù)組存儲

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

JavaScript二叉樹及遍歷算法實例分析

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

JavaScript二叉樹及遍歷算法實例分析

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

JavaScript二叉樹及遍歷算法實例分析

可以很明顯的看到存儲空間的浪費。

鏈表存儲

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

JavaScript二叉樹及遍歷算法實例分析

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

JavaScript二叉樹及遍歷算法實例分析

與二叉樹相關(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é)點;

  • 訪問根節(jié)點的left

  • 訪問根節(jié)點的right

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

實現(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)先遍歷

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

  • 創(chuàng)建隊列,把根節(jié)點入隊

  • 把對頭出隊并訪問

  • 把隊頭的leftright依次入隊

  • 重復執(zhí)行2、3步,直到隊列為空

實現(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
 */

先序遍歷

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

  • 訪問根節(jié)點;

  • 對當前節(jié)點的左子樹進行先序遍歷;

  • 對當前節(jié)點的右子樹進行先序遍歷;

如下圖所示:

JavaScript二叉樹及遍歷算法實例分析

遞歸方式實現(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
*/

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

// 非遞歸版
function preorder(root) {
  if (!root) return
  // 定義一個棧,用于存儲數(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
*/

中序遍歷

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

  • 對當前節(jié)點的左子樹進行中序遍歷;

  • 訪問根節(jié)點;

  • 對當前節(jié)點的右子樹進行中序遍歷;

如下圖所示:

JavaScript二叉樹及遍歷算法實例分析

遞歸方式實現(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
*/

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

// 非遞歸版
function inorder(root) {
  if (!root) return
  const stack = []
  // 定義一個指針
  let p = root
  // 如果棧中有數(shù)據(jù)或者p不是null,則繼續(xù)遍歷
  while (stack.length || p) {
    // 如果p存在則一致將p入棧并移動指針
    while (p) {
      // 將 p 入棧,并以移動指針
      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
*/

后序遍歷

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

  • 對當前節(jié)點的左子樹進行后序遍歷;

  • 對當前節(jié)點的右子樹進行后序遍歷;

  • 訪問根節(jié)點;

如下圖所示:

JavaScript二叉樹及遍歷算法實例分析

遞歸方式實現(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
*/

迭代方式實現(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)于“JavaScript二叉樹及遍歷算法實例分析”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI