面试基础-二叉树的相关基本算法

67 阅读3分钟

核心要点:创建一个栈,此栈可以视为一个当前需要遍历的一个棵树,将树推入栈中,然后遍历的口诀进行写算法,后序遍历需要额外注意重复访问的问题。

1.前序遍历

// root是一个左右结构的二叉树

var preorderTraversal = function (root) {
      const result = [];
      const stack = [];
      let current = root;
      while (current || stack.length > 0) {
        while (current) {
          result.push(current.val);
          stack.push(current);
          current = current.left;
        }
        current = stack.pop();
        current = current.right;
      }
      return result;
    };

2.中序遍历

var inorderTraversal = function (root) {
      const result = [];
      const stack = [];
      let current = root;
      while (current || stack.length > 0) {
        while (current) {
          stack.push(current);
          current = current.left;
        }
        current = stack.pop();
        result.push(current.val);
        current = current.right;
      }
      return result;
    };

3.后序遍历

var postorderTraversal = function (root) {
      const result = [];
      const stack = [];
      let last = null; // 标记上一个访问的节点
      let current = root;
      while (current || stack.length > 0) {
        while (current) {
          stack.push(current);
          current = current.left;
        }
        current = stack[stack.length - 1];
        if (!current.right || current.right == last) {
          current = stack.pop();
          result.push(current.val);
          last = current;
          current = null; // 继续弹栈
        } else {
          current = current.right;
        }
      }
      return result;
    }

4.二叉搜索树,寻找第k小的元素(k从1开始计算)

二叉搜索树的概念:又称二叉排序树, 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。

时间复杂度:O(n),空间复杂度:O(n)

//递归实现
    function KthNode(pRoot, k) {
      const arr = [];
      loopThrough(pRoot, arr);
      if (k > 0 && k <= arr.length) {
        return arr[k - 1];
      }
      return null;
    }

    function loopThrough(node, arr) {
      if (node) {
        loopThrough(node.left, arr);
        arr.push(node);
        loopThrough(node.right, arr);
      }
    }


    //非递归实现
    function KthNode(pRoot, k) {
      const arr = [];
      const stack = [];
      let current = pRoot;
      while (stack.length > 0 || current) {
        while (current) {
          stack.push(current);
          current = current.left;
        }
        current = stack.pop();
        arr.push(current);
        current = current.right;
      }
      if (k > 0 && k <= arr.length) {
        return arr[k - 1];
      }
      return null;
    }

5.二叉搜索树的后序遍历

题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。

思路:关键是给定的后序遍历的数组,数组的最后一位必然是根节点,只需先找按顺序找出比根元素小的值,即该数组为左子树,剩余的便是比根元素大的值,即该数组为右子树。

function VerifySquenceOfBST(sequence) {
  if (sequence && sequence.length > 0) {
    var root = sequence[sequence.length - 1]
    for (var i = 0; i < sequence.length - 1; i++) {
      if (sequence[i] > root) {
        break;
      }
    }
    for (let j = i; j < sequence.length - 1; j++) {
      if (sequence[j] < root) {
        return false;
      }
    }
    var left = true;
    if (i > 0) {
      left = VerifySquenceOfBST(sequence.slice(0, i));
    }
    var right = true;
    if (i < sequence.length - 1) {
      right = VerifySquenceOfBST(sequence.slice(i, sequence.length - 1));
    }
    return left && right;
  }
}

6.二叉树的下一个节点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

  • 右节点不为空 - 取右节点的最左侧节点
  • 右节点为空 - 如果节点是父亲节的左节点 取父节点
  • 右节点为空 - 如果节点是父亲节的右节点 父节点已经被遍历过,再往上层寻找...
  • 左节点一定在当前节点之前被遍历过
/*function TreeLinkNode(x){
    this.val = x;
    this.left = null;
    this.right = null;
    this.next = null;
}*/


// 找两个地方,第一个是
function getGetNext(pNode){
  if(!pNode){
    return null
  }
  if(pNode.right){
    pNode = pNode.right;
    while(pNode.left){
      pNode = pNode.left;
    }
    return pNode
  }else{
    if (!pNode.next) {
          return null;
        } else if (pNode == pNode.next.left) {
          return pNode.next;
        }
        pNode = pNode.next;
      }
      return pNode;
  }
}

7.比较一棵树是否是另一棵树的子树

首先找到A树中和B树根节点相同的节点

从此节点开始,递归AB树比较是否有不同节点

function compare(A,B){
    if(B === null){
        return true
    }
    if(A === null){
        return false
    }
    if(A.val !== B.val){
        return false
    }
    return compare(A.left, B.left) && compare(A.right, B.right)
}

var isSubStructure = function(A, B) {
    let result = false
    if(A && B){
        // 判断两棵树是否完全相等
        if(A.val === B.val){
            result = compare(A, B);
        }
        // 判断左子树
        if(!result){
            result = isSubStructure(A.left, B);
        }
        // 判断右子树
        if(!result){
            result = isSubStructure(A.right, B);
        }
    }
    return result
};