经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » JavaScript » 查看文章
前端数据结构--二叉树先序、中序、后序 递归、非递归遍历
来源:cnblogs  作者:风吹De麦浪  时间:2021/5/10 18:53:18  对本文有异议

二叉树遍历

二叉树的遍历是指从根节点出发,按照某种顺序依次访问所有节点,而且只访问一次,二叉树的遍历方式很多,如果限制了从左到右的方式,那么主要有4种:

  1. 前序遍历:根左右
  2. 中序遍历:左根右
  3. 后续遍历:左右根
  4. 层序遍历:按层级、从上到下,在同一层从左到右遍历

以上一篇的二叉树为例子,先序遍历 先访问根节点,在访问左节点,在访问右节点,如图:

  • 先(根)序遍历(根左右):A、B、D、E、C、F、G
  • 中(根)序遍历(左根右) : D、B、E、A、F、C、G
  • 后(根)序遍历(左右根) : D、E、B、F、G、C、A
  • 层序序遍历(上到下,左到右):A、B、C、D、E、F、G

递归实现先序、中序、后序、层序遍历

  二叉树的创建用上一篇链表方法存储的二叉树,只不过增加了4个遍历的方法而已。一颗大的树都是若干颗小树(根节点、左节点、右节点)构成,根节点也有可能是其他节点的左子树(树的根节点除外),所以递归遍历就是不断的递归子树的过程。

  1. 1 /*
  2. 2 * @Description:
  3. 3 * @Version: 1.0
  4. 4 * @Autor: longbs
  5. 5 */
  6. 6 class Node {
  7. 7 constructor (data = '#') {
  8. 8 this.data = data
  9. 9 this.lNode = null
  10. 10 this.rNode = null
  11. 11 }
  12. 12 }
  13. 13
  14. 14 class BiTree {
  15. 15 root = null
  16. 16 nodeList = []
  17. 17 constructor (nodeList) {
  18. 18 this.root = new Node()
  19. 19 this.nodeList = nodeList
  20. 20 }
  21. 21 createNode (node) {
  22. 22 const data = this.nodeList.shift()
  23. 23 if (data === '#') return
  24. 24 node.data = data
  25. 25 // 下一个元素是不是空节点, 如果不是创建左节点
  26. 26 if (this.nodeList[0] !== '#') {
  27. 27 node.lNode = new Node(data)
  28. 28 }
  29. 29 this.createNode(node.lNode)
  30. 30
  31. 31 // 下一个元素是不是空节点, 如果不是创建右节点
  32. 32 if (this.nodeList[0] !== '#') {
  33. 33 node.rNode = new Node(data)
  34. 34 }
  35. 35 this.createNode(node.rNode)
  36. 36
  37. 37 }
  38. 38 preorderTraverse (node) {
  39. 39 if (node === null) return
  40. 40 console.log(node.data)
  41. 41 this.preorderTraverse(node.lNode)
  42. 42 this.preorderTraverse(node.rNode)
  43. 43 }
  44. 44 inorderTraverse (node) {
  45. 45 if (node === null) return
  46. 46 this.inorderTraverse(node.lNode)
  47. 47 console.log(node.data)
  48. 48 this.inorderTraverse(node.rNode)
  49. 49 }
  50. 50 postorderTraverse (node) {
  51. 51 if (node === null) return
  52. 52 this.postorderTraverse(node.lNode)
  53. 53 this.postorderTraverse(node.rNode)
  54. 54 console.log(node.data)
  55. 55 }
  56. 56 sequenceTraverse (root) {
  57. 57 if (!root) return
  58. 58 let queue = []
  59. 59 queue.push(root)
  60. 60 while (queue.length) {
  61. 61 const node = queue.shift()
  62. 62 console.log(node.data)
  63. 63 if(node.lNode) {
  64. 64 queue.push(node.lNode)
  65. 65 }
  66. 66 if (node.rNode) {
  67. 67 queue.push(node.rNode)
  68. 68 }
  69. 69 }
  70. 70 }
  71. 71 }
  72. 72
  73. 73 let arr = ['A','B','D','#','#','E','#','#','C','F','#', '#', 'G', '#', '#']
  74. 74 let bi = new BiTree(arr)
  75. 75 bi.createNode(bi.root)
  76. 76 console.log(bi.root)
  77. 77
  78. 78 console.log('----先序----')
  79. 79 console.log(bi.preorderTraverse(bi.root))
  80. 80
  81. 81 console.log('----中序----')
  82. 82 console.log(bi.inorderTraverse(bi.root))
  83. 83
  84. 84 console.log('----后序----')
  85. 85 console.log(bi.postorderTraverse(bi.root))
  86. 86
  87. 87 console.log('----层序----')
  88. 88 console.log(bi.sequenceTraverse(bi.root))

层级遍历使用了队列来实现,思路也比较简单,一开始入队根节点,出队最后一个节点,出队时把相关左节点、右节点入队,如此循环,队列为空即遍历完成。

非递归实现先序、中序、后序

二叉树的递归遍历非常容易理解,但因为是递归调用需要在内存栈中分配内存用来保存参数,层数多了内存容易溢出。

非递归先序基本思路:使用数组来模拟栈的数据结构,首先根节点入栈,然后出栈,在出栈的时候把相关需要的节点按要求把左右节点入栈,如此循环一直到这个栈为空。

步骤:

  1. 根节点放入栈
  2. 取出栈顶的节点,把该节点结果放入数组
  3. 如果该右节点存在,将该节点右节点放入栈
  4. 如果该左节点存在,将该节点左节点放入栈
  5. 重复 2-4
  6. 栈为空退出循环
  1. 1 /*
  2. 2 非递归:用栈来模拟递归
  3. 3 */
  4. 4 preorderNonRecursion (root) {
  5. 5 if (!root) return ''
  6. 6 let stack = []
  7. 7 let result = []
  8. 8 stack.push(root)
  9. 9 while (stack.length) {
  10. 10 const node = stack.pop()
  11. 11 result.push(node.data)
  12. 12
  13. 13 // 如果存在右节点,先压入右节点
  14. 14 if (node.rNode) {
  15. 15 stack.push(node.rNode)
  16. 16 }
  17. 17 if (node.lNode) {
  18. 18 stack.push(node.lNode)
  19. 19 }
  20. 20 }
  21. 21 return result
  22. 22 }

中序、后序代码基本思路类似代码如下:

  1. 1 // 非递归-中序
  2. 2 inorderNonRecursion (root) {
  3. 3 if (!root) return ''
  4. 4 let stack = []
  5. 5 let result = []
  6. 6 // stack.push(root)
  7. 7 while (root !== null || stack.length) {
  8. 8 // 找到左节点
  9. 9 while (root !== null) {
  10. 10 stack.push(root)
  11. 11 root = root.lNode
  12. 12 }
  13. 13 root = stack.pop()
  14. 14 result.push(root.data)
  15. 15 // 右节点
  16. 16 root = root.rNode
  17. 17 }
  18. 18 return result
  19. 19 }
  20. 20 // 非递归-后序
  21. 21 postorderNonRecursion (root) {
  22. 22 if (!root) return ''
  23. 23 let stack = []
  24. 24 let result = []
  25. 25 stack.push(root)
  26. 26 while (stack.length) {
  27. 27 const node = stack.pop()
  28. 28 result.unshift(node.data)
  29. 29
  30. 30 if (node.lNode) {
  31. 31 stack.push(node.lNode)
  32. 32 }
  33. 33 if (node.rNode) {
  34. 34 stack.push(node.rNode)
  35. 35 }
  36. 36 }
  37. 37 return result
  38. 38 }

递归遍历、非递归遍历完整代码

  1. /*
  2. * @Description:
  3. * @Version: 1.0
  4. * @Autor: longbs
  5. */
  6. class Node {
  7. constructor (data = '#') {
  8. this.data = data
  9. this.lNode = null
  10. this.rNode = null
  11. }
  12. }
  13. class BiTree {
  14. root = null
  15. nodeList = []
  16. constructor (nodeList) {
  17. this.root = new Node()
  18. this.nodeList = nodeList
  19. }
  20. // 创建二叉树
  21. createNode (node) {
  22. const data = this.nodeList.shift()
  23. if (data === '#') return
  24. node.data = data
  25. // 下一个元素是不是空节点, 如果不是创建左节点
  26. if (this.nodeList[0] !== '#') {
  27. node.lNode = new Node(data)
  28. }
  29. this.createNode(node.lNode)
  30. // 下一个元素是不是空节点, 如果不是创建右节点
  31. if (this.nodeList[0] !== '#') {
  32. node.rNode = new Node(data)
  33. }
  34. this.createNode(node.rNode)
  35. }
  36. // 先序
  37. preorderTraverse (node) {
  38. if (node === null) return
  39. console.log(node.data)
  40. this.preorderTraverse(node.lNode)
  41. this.preorderTraverse(node.rNode)
  42. }
  43. // 中序
  44. inorderTraverse (node) {
  45. if (node === null) return
  46. this.inorderTraverse(node.lNode)
  47. console.log(node.data)
  48. this.inorderTraverse(node.rNode)
  49. }
  50. // 后序
  51. postorderTraverse (node) {
  52. if (node === null) return
  53. this.postorderTraverse(node.lNode)
  54. this.postorderTraverse(node.rNode)
  55. console.log(node.data)
  56. }
  57. // 层序
  58. sequenceTraverse (root) {
  59. if (!root) return
  60. let queue = []
  61. queue.push(root)
  62. while (queue.length) {
  63. const node = queue.shift()
  64. console.log(node.data)
  65. if(node.lNode) {
  66. queue.push(node.lNode)
  67. }
  68. if (node.rNode) {
  69. queue.push(node.rNode)
  70. }
  71. }
  72. }
  73. /*
  74. 非递归-先序
  75. 用栈来模拟递归
  76. */
  77. preorderNonRecursion (root) {
  78. if (!root) return ''
  79. let stack = []
  80. let result = []
  81. stack.push(root)
  82. while (stack.length) {
  83. const node = stack.pop()
  84. result.push(node.data)
  85. // 如果存在右节点,先压入右节点
  86. if (node.rNode) {
  87. stack.push(node.rNode)
  88. }
  89. if (node.lNode) {
  90. stack.push(node.lNode)
  91. }
  92. }
  93. return result
  94. }
  95. // 非递归-中序
  96. inorderNonRecursion (root) {
  97. if (!root) return ''
  98. let stack = []
  99. let result = []
  100. // stack.push(root)
  101. while (root !== null || stack.length) {
  102. // 找到左节点
  103. while (root !== null) {
  104. stack.push(root)
  105. root = root.lNode
  106. }
  107. root = stack.pop()
  108. result.push(root.data)
  109. // 右节点
  110. root = root.rNode
  111. }
  112. return result
  113. }
  114. // 非递归-后序
  115. postorderNonRecursion (root) {
  116. if (!root) return ''
  117. let stack = []
  118. let result = []
  119. stack.push(root)
  120. while (stack.length) {
  121. const node = stack.pop()
  122. result.unshift(node.data)
  123. if (node.lNode) {
  124. stack.push(node.lNode)
  125. }
  126. if (node.rNode) {
  127. stack.push(node.rNode)
  128. }
  129. }
  130. return result
  131. }
  132. }
  133. let arr = ['A','B','D','#','#','E','#','#','C','F','#', '#', 'G', '#', '#']
  134. let bi = new BiTree(arr)
  135. bi.createNode(bi.root)
  136. console.log(bi.root)
  137. console.log('----递归先序----')
  138. console.log(bi.preorderTraverse(bi.root))
  139. console.log('----非递归先序----')
  140. console.log(bi.preorderNonRecursion(bi.root))
  141. console.log('----递归中序----')
  142. console.log(bi.inorderTraverse(bi.root))
  143. console.log('----非递归中序----')
  144. console.log(bi.inorderNonRecursion(bi.root))
  145. console.log('----递归后序----')
  146. console.log(bi.postorderTraverse(bi.root))
  147. console.log('----非递归后序----')
  148. console.log(bi.postorderNonRecursion(bi.root))
  149. console.log('----层序----')
  150. console.log(bi.sequenceTraverse(bi.root))

 

 

原文链接:http://www.cnblogs.com/longbensong/p/14752101.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号