国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > JS > 正文

JS中的二叉樹遍歷詳解

2024-05-06 16:29:47
字體:
來源:轉載
供稿:網友
這篇文章主要為大家詳細介紹了JS中的二叉樹遍歷,何為二叉樹,什么是二叉樹的遍歷,感興趣的小伙伴們可以參考一下
 

二叉樹是由根節點,左子樹,右子樹組成,左子樹和友子樹分別是一個二叉樹。
這篇文章主要在JS中實現二叉樹的遍歷。

一個二叉樹的例子

var tree = { value: 1, left: {  value: 2,  left: {   value: 4  } }, right: {  value: 3,  left: {   value: 5,   left: {    value: 7   },   right: {    value: 8   }  },  right: {   value: 6  } }}

廣度優先遍歷
廣度優先遍歷是從二叉樹的第一層(根結點)開始,自上至下逐層遍歷;在同一層中,按照從左到右的順序對結點逐一訪問。
實現:
<!--more-->
使用數組模擬隊列。首先將根節點歸入隊列。當隊列不為空的時候,執行循環:取出隊列的一個節點,如果該結點的左子樹為非空,則將該結點的左子樹入隊列;如果該結點的右子樹為非空,則將該結點的右子樹入隊列。
(描述有點不清楚,直接看代碼吧。)

var levelOrderTraversal = function(node) {  if(!node) {    throw new Error('Empty Tree') }  var que = [] que.push(node)  while(que.length !== 0) {  node = que.shift()    console.log(node.value)    if(node.left) que.push(node.left)    if(node.right) que.push(node.right) }}

遞歸遍歷
覺得用這幾個字母表示遞歸遍歷的三種方法不錯:
D:訪問根結點,L:遍歷根結點的左子樹,R:遍歷根結點的右子樹。
先序遍歷:DLR
中序遍歷:LDR
后序遍歷:LRD

順著字母表示的意思念下來就是遍歷的順序了 ^ ^

這3種遍歷都屬于遞歸遍歷,或者說深度優先遍歷(Depth-First Search,DFS),因為它總
是優先往深處訪問。

先序遍歷的遞歸算法:

var preOrder = function (node) {  if (node) {    console.log(node.value);  preOrder(node.left);  preOrder(node.right); }}

中序遍歷的遞歸算法:

var inOrder = function (node) {  if (node) {  inOrder(node.left);    console.log(node.value);  inOrder(node.right); }}

后序遍歷的遞歸算法:

var postOrder = function (node) {  if (node) {  postOrder(node.left);  postOrder(node.right);    console.log(node.value); }}

非遞歸深度優先遍歷
其實對于這些概念誰是屬于誰的我也搞不太清楚。有的書里將二叉樹的遍歷只講了上面三種遞歸遍歷。有的分廣度優先遍歷和深度優先遍歷兩種,把遞歸遍歷都分入深度遍歷當中;有的分遞歸遍歷和非遞歸遍歷兩種,非遞歸遍歷里包括廣度優先遍歷和下面這種遍歷。個人覺得怎么分其實并不重要,掌握方法和用途就好 :)

剛剛在廣度優先遍歷中使用的是隊列,相應的,在這種不遞歸的深度優先遍歷中我們使用棧。在JS中還是使用一個數組來模擬它。
這里只說先序的:
額,我嘗試了描述這個算法,然而并描述不清楚,按照代碼走一邊你就懂了。

var preOrderUnRecur = function(node) {  if(!node) {    throw new Error('Empty Tree') }  var stack = [] stack.push(node)  while(stack.length !== 0) {  node = stack.pop()    console.log(node.value)    if(node.right) stack.push(node.right)    if(node.left) stack.push(node.left) }}

看了這一篇,找到了非遞歸后序的算法,所以在這里把非遞歸的遍歷方法補充完整。
非遞歸中序
先把數的左節點推入棧,然后取出,再推右節點。

var inOrderUnRecur = function(node) {  if(!node) {    throw new Error('Empty Tree') }  var stack = []  while(stack.length !== 0 || node) {    if(node) {   stack.push(node)   node = node.left  } else {   node = stack.pop()      console.log(node.value)   node = node.right  } }}

非遞歸后序(使用一個棧)
這里使用了一個臨時變量記錄上次入棧/出棧的節點。思路是先把根節點和左樹推入棧,然后取出左樹,再推入右樹,取出,最后取跟節點。

var posOrderUnRecur = function(node) {  if(!node) {    throw new Error('Empty Tree') }  var stack = [] stack.push(node)  var tmp = null while(stack.length !== 0) {  tmp = stack[stack.length - 1]    if(tmp.left && node !== tmp.left && node !== tmp.right) {   stack.push(tmp.left)  } else if(tmp.right && node !== tmp.right) {   stack.push(tmp.right)  } else {      console.log(stack.pop().value)   node = tmp  } }}

非遞歸后序(使用兩個棧)
這個算法的思路和上面那個差不多,s1有點像一個臨時變量。

var posOrderUnRecur = function(node) {  if(node) {    var s1 = []    var s2 = []  s1.push(node)    while(s1.length !== 0) {   node = s1.pop()   s2.push(node)      if(node.left) {    s1.push(node.left)   }      if(node.right) {    s1.push(node.right)   }  }    while(s2.length !== 0) {      console.log(s2.pop().value);  } }}

Morris遍歷
這個方法即不用遞歸也不用棧實現三種深度遍歷,空間復雜度為O(1)(這個概念我也不是特別清楚org)
(這三種算法我先放著,有空再研究)
Morris先序:

var morrisPre = function(head) {  if(!head) {    return }  var cur1 = head,   cur2 = null while(cur1) {  cur2 = cur1.left    if(cur2) {      while(cur2.right && cur2.right != cur1) {    cur2 = cur2.right   }      if(!cur2.right) {    cur2.right = cur1        console.log(cur1.value)    cur1 = cur1.left        continue   } else {    cur2.right = null   }  } else {       console.log(cur1.value)  }  cur1 = cur1.right }}

Morris中序:

var morrisIn = function(head) {  if(!head) {    return }  var cur1 = head,   cur2 = null while(cur1) {  cur2 = cur1.left    if(cur2) {      while(cur2.right && cur2.right !== cur1) {    cur2 = cur2.right   }      if(!cur2.right) {    cur2.right = cur1    cur1 = cur1.left        continue   } else {    cur2.right = null   }  }    console.log(cur1.value)  cur1 = cur1.right }}

Morris后序:

var morrisPost = function(head) {  if(!head) {    return }  var cur1 = head,   cur2 = null while(cur1) {  cur2 = cur1.left    if(cur2) {      while(cur2.right && cur2.right !== cur1) {    cur2 = cur2.right   }      if(!cur2.right) {    cur2.right = cur1    cur1 = cur1.left        continue   } else {    cur2.right = null    printEdge(cur1.left)   }  }  cur1 = cur1.right } printEdge(head)}var printEdge = function(head) { 

以上就是本文的全部內容,希望對大家的學習有所幫助。



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 江都市| 荣成市| 石渠县| 旌德县| 枞阳县| 涟源市| 买车| 宁远县| 日喀则市| 临泉县| 女性| 曲沃县| 彭州市| 龙里县| 金昌市| 白玉县| 天台县| 清流县| 嘉兴市| 铜山县| 尉犁县| 措美县| 全椒县| 璧山县| 土默特左旗| 泸州市| 林芝县| 海晏县| 宁晋县| 巢湖市| 铜陵市| 湟源县| 玛曲县| 咸阳市| 宁乡县| 嘉兴市| 正安县| 安图县| 紫金县| 剑川县| 海淀区|