[数据结构学习笔记19] 二叉树遍历(Binary Tree Traversal)

树是分等级的数据结构,遍历树有两种策略,一是广度优先,一是深度优先。

广度优先

                          a                               level 0

                      |           |

                    b             c                      level 1

                |       |         |      |

              d        e       f      g                 level 2

            |    |

           h    i                                         level 3

广度优先,我们从level 0开始,每层节点访问完毕,接着往下一层。

a,b,c,d,e,f,g,h,i,基本是从上往下,从左往右,广度优先比较符合我们的正常思维。

深度优先

一直往左,往下,直到叶子节点,然后往回,访问另一个分支。

a,b,d,h(h是往下,往左的最后的叶子节点,开始回溯到d,访问d的右节点i),i(i访问完毕,接着回溯到b,访问b的右节点e),e(e访问完毕,接着回溯到a,访问a的右节点c),c(c有左孩子节点f),f(回溯到c,访问c右节点g),g

基本思路:

1. 访问root节点

2. 访问左边的子树

3. 访问右边的子树

我们有几个深度优先的变种,前序遍历,中序遍历,后序遍历。

 

遍历方法实现

两个步骤

1. 节点被发现,这个是说该节点被发现存在;

2. 节点被访问过,这个是说该节点被检查了,并且是否有子节点需要遍历。

 

先看广度优先:

维护两个数组:

explored;discovered。

从root开始:

explored = [a]; discovered = []

a有两个子节点b,c,从左节点开始一次放入discovered

explored = [a]; discovered = [b, c]

然后到b,b也有两个孩子节点,从左往右,放入discovered

explored = [a, b]; discovered = [c, d, e]

然后到c,一样的操作,一直到最后一个叶子节点

explored = [a, b, c]; discovered = [d, e, f, g]

explored = [a, b, c, d]; discovered = [e, f, g, h, i]

... 

explored = [a, b, c, d, e, f, g, h, i]; discovered = []

广度优先,discovered其实是个queue结构,节点从头移出,从尾加入。

 

深度优先

discovered集合里的节点,我们不是从左往右了,而是从右往左。下一个要检查(explore)的节点,是我们发现(discovered)的最后的节点。

从root开始:

explored = [a]; discovered = [c, b]

从discovered末尾拿下一个explore的节点b

explored = [a, b]; discovered = [c, e, d]

explored = [a, b, d]; discovered = [c, e, i, h]

explored = [a, b, d, h]; discovered = [c, e, i]

explored = [a, b, d, h, i]; discovered = [c, e]

explored = [a, b, d, h, i, e]; discovered = [c]

explored = [a, b, d, h, i, e, c]; discovered = [g, f] // 这里到了右半部分

explored = [a, b, d, h, i, e, c, f]; discovered = [g]

explored = [a, b, d, h, i, e, c, f, g]; discovered = []

广度优先,discovered其实是个stack结构,节点从尾部进入,从尾部出。

 

代码实现(javascript)

先构造二叉树

复制代码
class Node {
  constructor(data) {
      this.data = data;
      this.left = null;
      this.right = null;
  }  
}

const rootNodeA = new Node("A");
const rootNodeA = new Node("B");
const rootNodeA = new Node("C");
const rootNodeA = new Node("D");
const rootNodeA = new Node("E");
const rootNodeA = new Node("F");
const rootNodeA = new Node("G");
const rootNodeA = new Node("H");
const rootNodeA = new Node("I");

rootNodeA.left = nodeB;
rootNodeA.right = nodeC;

nodeB.left = nodeD;
nodeB.right = nodeE;

nodeC.left = nodeF;
nodeC.right = nodeG;

nodeD.left = nodeH;
nodeD.right = nodeI;
复制代码

广度优先

复制代码
function breadthFirstTraversal(root) {
   if (!root) {
       return;
   }  

   let explored = [];
   // create a queue and add the root to it
   const discovered = new Queue();
   discovered.enqueue(root);

   while (discovered.length > 0) {
       // remove the first item from queue
       const current = discovered.dequeue();

       // process the current node
       explored.push(current);

       // store all unvisited children of the current node
       if (current.left) {
           discovered.enqueue(current.left);
       }
       if (current.right) {
           discovered.enqueue(current.right);
       }
   }
   return explored;
}
复制代码

Queue的实现在这里

let fullTree = breadthFirstTraversal(rootNodeA);
console.log(fullTree);

 

深度优先

复制代码
function depthFirstTraversal(root) {
  if (!root) {
     return;
  }

   let explored = [];
   
   // create a stack and add the root to it
   const discovered = new Stack();
   discovered.push(root);

   while (discovered.length > 0) {
      // remove the last item from our list of discovered nodes
      const current = discovered.pop();
      // Process the current node
      explored.push(current);

      // store all unvisited children of the current node in reverse order
      if (current.right) {
          discovered.push(current.right);
      }
      if (current.left) {
          discovered.push(current.left);
      }
   }  

   return explored;
}
复制代码

Stack的实现在这里

let fullTreeTwo = depthFirstTraversal(rootNodeA);
console.log(fullTreeTwo);

二叉树的遍历,深度优先、广度优先的时间复杂度和空间复杂度都是O(n)。

 

总结一下

1. 广度优先,按层从左往右访问节点

2. 深度优先,顺着分支访问节点,直到叶子节点,然后开始回溯

 

posted @   Eagle6970  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验
点击右上角即可分享
微信分享提示