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