树的遍历
树的前序遍历

- 迭代实现
var preorderTraversal = function(root) {
let list = [];
let result = [];
if (!root) return result;
list.push({
color:'white',
node:root
})
while (list.length > 0) {
let temp = list.pop(); // 取出list中最后一个节点;
let {color,node} = temp;
// white表示该节点的左右子树还没有被添加进list存储
if (color === 'gary') {
result.push(node.val);
} else {
// 前序遍历的顺序为根节点-> 左子树 -> 右子树,因为每一次都是取出最后一个元素,
// 而push方法没次都将元素追加到最后面,所以最先出list的应该最后加入
node.right && list.push({color:'white',node:node.right});
node.left && list.push({color:'white',ndoe:node.left});
list.push({color:'gray',node})
}
}
}
- 递归实现
var preorderTraversal = function(root) {
if (root) {
return [root.val,...preorderTraversal(root.left),...preorderTraversal(root.right)]
} else {
return []
}
}
树的中序遍历

- 迭代实现
var inorderTraversal = function(root) {
let list = [];
let result = [];
if(!root) return result;
list.push({
color:"white",
node:root
})
while(list.length > 0){
let {color,node} = list.pop();
if(color === "gray"){
result.push(node.val)
}else{
// 与上面原理相同
node.right && list.push({color:"white",node:node.right});
list.push({color:"gray",node})
node.left && list.push({color:"white",node:node.left});
}
}
return result;
};
- 递归实现
var inorderTraversal = function(root) {
if(root) {
return [...inorderTraversal(root.left),root.val,...inorderTraversal(root.right)]
}
else{
return []
}
}
后续遍历

- 迭代实现
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var postorderTraversal = function(root) {
let result = [];
let stack = [];
if(!root) return result;
stack.push({
color:"white",
node:root
});
while(stack.length > 0) {
let {color,node} = stack.pop();
if(color === "gray"){
result.push(node.val);
}else{
stack.push({color:"gray",node});
node.right && stack.push({color:"white",node:node.right});
node.left && stack.push({color:"white",node:node.left});
}
}
return result;
};
- 递归实现
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var postorderTraversal = function(root) {
递归实现
if(root){
return [...postorderTraversal(root.left),...postorderTraversal(root.right),root.val]
}else{
return []
}
}
层序遍历
思路:实际上就是对广度优先遍历的一个变型,需要加一个size来记录每一层值的数量,并且将每一层放置在一个数组里加以保存。
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrder = function(root) {
let order = [];
let result = [];
if (!root) return [];
order.push(root);
while(order.length > 0) {
let item = [];
let size = order.length;
// 将该层的每一个节点的左右孩子放置在order中,将该层的所有节点放置在item中,放完后添加至result中
while(size > 0) {
let node = order.shift();
item.push(node.val);
node.left && order.push(node.left);
node.right && order.push(node.right);
size--;
}
result.push(item);
}
return result;
}
根据遍历的结果构造二叉树
根据中序遍历与后序遍历构造二叉树
思路:构造二叉树主要有以下步骤:
① 找到根节点来分割左子树和右子树。
② 使用递归的思维求得根节点。
从后续遍历中,可以得知后续遍历数组中最后一个节点就是根节点,得到根节点后从中序遍历中查找根节点的位置,根节点位置之前为左子树,根节点位置之后为右子树。
还有另一个技巧是“两种遍历中,同一子树的节点数目是相同的”,如:
中序遍历中,我们知道 左子树:[inorder_start,index-1], 右子树:[index+1, inorder_end]
在后序遍历中,左子树起始位置为post_start,左子树一共有(index-1 - inorder_start + 1)个,因此左子树:[post_start, post_start + (index-1 - inorder_start)],后面的均为右子树和根节点部分且右子树的终止位置为post_end - 1。
实现代码如下:
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {number[]} inorder
* @param {number[]} postorder
* @return {TreeNode}
*/
var buildTree = function(inorder, postorder) {
if (!postorder.length) return null;
const top = postorder.pop();
const root = new TreeNode(top);
const topIndex = inorder.indexOf(top);
root.left = buildTree(inorder.slice(0, topIndex), postorder.slice(0, topIndex));
root.right = buildTree(inorder.slice(topIndex + 1), postorder.slice(topIndex));
return root;
};
根据前序遍历与中序遍历构造二叉树
思路:① 根据前序遍历,我们知道前序遍历列表中第一个元素就是根节点,将根节点的值去中序列表中查找,知道根节点在中序列表中的位置,那么中序列表中该位置之前的节点为左子树,该位置之后的节点为右子树。
② 从而我们可以得知该二叉树中的左右子树节点的个数,设左子树的节点数量为x。前序列表中从第二个节点开始为左子树的根节点,然后再往右数x-1个位置即可,后面的均为右子树的节点。
代码如下:
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {number[]} preorder
* @param {number[]} inorder
* @return {TreeNode}
*/
var buildTree = function(preorder, inorder) {
if(!preorder.length) return null;
const root = new TreeNode(preorder[0]);
let index = inorder.indexOf(root.val);
root.left = buildTree(preorder.slice(1,index + 1),inorder.slice(0,index));
root.right = buildTree(preorder.slice(index + 1),inorder.slice(index + 1))
return root;
};
根据前序遍历与后序遍历构造二叉树
思路:
① 首先我们可以显然知道当前根节点为pre[pre_start],并且它在后序中的位置为post_end,因此这里我们需要找到能区分左右子树的节点。
我们知道左子树的根节点为pre[pre_start+1],因此只要找到它在后序中的位置就可以分开左右子树(index的含义)
② 后序遍历中,我们知道 左子树:[post_start,index], 右子树:[index+1, post_end-1]在前序遍历中,左子树起始位置为pre_start+1,左子树个数一共有(index - post_start)个,因此左子树:[pre_start+1, pre_start+1 + (index - post_start)]
右子树起始位置为左子树终止位置+1,终止位置为pre_end,因此右子树:[ pre_start+1 + (index - post_start) + 1, pre_end]
代码实现如下:
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {number[]} preorder
* @param {number[]} inorder
* @return {TreeNode}
*/
var buildTree = function(preorder, postorder) {
if(!preorder.length) return null;
let end = postorder.pop();
let root = new TreeNode(end);
let index = postorder.indexOf(preorder[1].val);
root.left = buildTree(preorder.slice(1,index + 1),postorder.slice(0,index));
root.right = buileTree(preorder.slice(index + 1),postorder.slice(index));
return root;
}
参考:
作者:christmas_wang
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/solution/kan-wo-jiu-gou-liao-san-chong-bian-li-fang-shi-g-2/
来源:力扣(LeetCode)
&spm=1001.2101.3001.5002&articleId=108299285&d=1&t=3&u=ec79008ad381486d80d50140be13d210)
1092

被折叠的 条评论
为什么被折叠?



