您好,登錄后才能下訂單哦!
這篇“JavaScript二叉樹及遍歷算法實例分析”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“JavaScript二叉樹及遍歷算法實例分析”文章吧。
二叉樹是每個節(jié)點最多只能有兩個子節(jié)點的樹,如下圖所示:
一個二叉樹具有以下幾個特質(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,則說明該二叉樹是一個滿二叉樹,
如下圖所示:
滿二叉樹除了滿足普通二叉樹特質(zhì),還具有如下幾個特質(zhì):
滿二叉樹的的第n
層具有2^(n-1)
個節(jié)點;
深度為k
的滿二叉樹一定存在2^k-1
個節(jié)點,葉子節(jié)點的個數(shù)為2^(k-1)
;
具有n
個節(jié)點的滿二叉樹的深度為log_2^(n+1)
。
如果一個二叉樹去掉最后一次層是滿二叉樹,且最后一次的節(jié)點是依次從左到右分布的,則這個二叉樹是一個完全二叉樹,
如下圖所示:
存儲二叉樹的常見方式分為兩種,一種是使用數(shù)組存儲,另一種使用鏈表存儲。
使用數(shù)組存儲二叉樹,如果遇到完全二叉樹,存儲順序從上到下,從左到右,如下圖所示:
如果是一個非完全二叉樹,如下圖所示:
需要先將其轉(zhuǎn)換為完全二叉樹,然后在進行存儲,如下圖所示:
可以很明顯的看到存儲空間的浪費。
使用鏈表存儲通常將二叉樹中的分為3個部分,如下圖:
這三個部分依次是左子樹的引用,該節(jié)點包含的數(shù)據(jù),右子樹的引用,存儲方式如下圖所示:
以下算法中遍歷用到的樹如下:
// 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)先遍歷思路一致,思路如下:
訪問根節(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 */
實現(xiàn)思路如下:
創(chuàng)建隊列,把根節(jié)點入隊
把對頭出隊并訪問
把隊頭的left
和right
依次入隊
重復執(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é)點的右子樹進行先序遍歷;
如下圖所示:
遞歸方式實現(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é)點的右子樹進行中序遍歷;
如下圖所示:
遞歸方式實現(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é)點;
如下圖所示:
遞歸方式實現(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è)資訊頻道。
免責聲明:本站發(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)容。