递归实现
思路:遍历左右结点获取深度,没下一层深度加1。
function BTMaxDeep(root) {
if (!root) {
return 0;
}
let maxLeft = BTMaxDeep(root.left);
let maxRight = BTMaxDeep(root.right);
const max = Math.max(maxLeft, maxRight);
return max + 1;
}
迭代实现
广度优先遍历
思路:要使用栈来存储每一层的结点,然后再遍历每个结点是否拥有孩子,有就用另一个栈存起来,然后不断替换。
function BTMaxDeepByBFS(root) {
if (!root) {
return 0;
}
let stack = []; //记录每一层的结点
let deep = 0;
stack.push(root);
while (stack.length > 0) {
//记录下一层的结点,因为push动作回导致数组长度变化,所以。。。
const arr = [];
//取出每个结点,判断每个结点是否存在左右孩子,有就存起来
stack.forEach(ele => {
if (ele.left) {
arr.push(ele.left);
}
if (ele.right) {
arr.push(ele.right);
}
})
//替换层栈, 同时深度加1
stack = arr;
deep++;
}
return deep;
}
深度优先遍历
这里的深度特别难搞,让我整个菜鸟卡了好久。
思路:同样要使用栈来存储结点,从根结点开始,先遍历所有左结点,然后再不断回退。
摘自数据结构(C语言版)清华大学:其一是递归调用的语句编号,其二是指向根节点的指针,则当栈顶记录中的指针非空时,应该遍历左子树,即指向左子树根的指针进栈。若栈顶记录中的指针值为空,则应该退至上一层,若是从左子树返回,则应访问当前层即栈顶记录中指针所指的根节点。若是从右子树返回,应继续退栈。
这里是中序遍历二叉树的代码:
Status InOrderTraverse(BiTree T, Status(* Visit)(TElemType e)){
//采用二叉链表存储结构,Visit是对数据元素操作的应用函数。
//中序遍历二叉树T的非递归算法,对每个数据元素调用函数Visit;
InitStack(S); Push(S,T); //根指针进栈
while(!StackEmpty(S)){
while(GetTop(S, p) && p Push(S, p->lchild);
Pop(S, p); //空指针退栈
if(!StackEmpty(S)){ //访问结点向右异步
Pop(S, p) if(!Visit(p->data)) return ERROR;
Push(S, p->rchild);
}
}
return OK;
}
这里是中序遍历二叉树并记录最深深度的js代码。再回退结点的时候和遍历右子树的时候卡了很久,后来就想到要记录每个结点的深度,这样回退的时候就知道当前遍历的深度是多少。
unction maxDeep3(root) {
if (!root) {
return 0;
}
const stack = []; //记录结点和每个结点的深度
let deep = 1,maxDeep = -Infinity;
stack.push({ root, deep });//根节点进栈
while (stack.length > 0) {
//每次取栈顶元素
root = stack[stack.length - 1].root;
while (root) {
root = root.left;
if(root){
deep++;
}
stack.push({ root: root, deep });
}
//空结点退栈
stack.pop();
if (stack.length > 0) {
const obj = stack.pop();
root = obj.root;
if (root.right) {
deep = obj.deep+1; //向右一步
}else{
maxDeep = maxDeep > deep ? maxDeep : deep;
}
stack.push({ root: root.right, deep });
}
}
return maxDeep;
}
声明:作者处于菜鸟阶段,还在不断学习,代码与思想仅供参考,欢迎指正。
复杂事往简单了去想,是拆解,是切割,就像一剑破万法,而将简单事往复杂了去想,是缝补,是搭建,是打造小天地。——《剑来》