二叉树可以链式存储,也可以顺序存储。
链式存储方式就用指针, 顺序存储的方式用数组。
二叉树链式存储定义
C++
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x): val(x), left(NULL), right(NULL) {}
};
Python
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
1. 二叉树的递归遍历
递归算法分三步来写:
- 确认递归函数的参数和返回值
- 确认终止条件
- 确认单层递归逻辑
(1)前序遍历
题目:给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
输入:root = [1,null,2,3]
输出:[1,2,3]
思路:前序:根——左——右
笔记:C++中push_back()
函数用于在vector最后添加一个元素。
C++:
class Solution {
public:
void preorder(TreeNode *root, vector<int> &res){
if (root == nullptr) return;
res.push_back(root->val);
preorder(root->left, res);
preorder(root->right, res);
}
vector<int> preorderTraversal(TreeNode *root) {
vector<int> res; //保存结果
preorder(root, res);
return res;
}
};
Python:
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
# 保存的结果
result = []
def preorder(root: TreeNode):
if root == None:
return
result.append(root.val)
preorder(root.left)
preorder(root.right)
preorder(root)
return result
(2)中序遍历
题目:给你二叉树的根节点 root ,返回它节点值的 中序 遍历。
输入:root = [1,null,2,3]
输出:[1,3,2]
思路:中序:左——根——右
C++:
class Solution {
public:
void inorder(TreeNode *root, vector<int> &res){
if(root == nullptr) return;
inorder(root->left, res);
res.push_back(root->val);
inorder(root->right, res);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
inorder(root, res);
return res;
}
};
Python:
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
def inorder(root: TreeNode):
if root == None:
return
inorder(root.left)
result.append(root.val)
inorder(root.right)
inorder(root)
return result
(3)后序遍历
题目:给你二叉树的根节点 root ,返回它节点值的 后序 遍历。
输入:root = [1,null,2,3]
输出:[3,2,1]
思路:后序:左——右——根
C++:
class Solution {
public:
void postorder(TreeNode *root, vector<int> &res){
if (root == nullptr) return;
postorder(root->left, res);
postorder(root->right, res);
res.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
postorder(root, res);
return res;
}
};
Python:
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
def postorder(root: TreeNode):
if root == None:
return
postorder(root.left)
postorder(root.right)
result.append(root.val)
postorder(root)
return result
2. 二叉树的迭代遍历
因为递归可以用过栈来实现:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。
(1)前序遍历
C++:
在这里插入代码片
Python:
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
if not root:
return result
stack = [root]
while stack:
node = stack.pop()
result.append(node.val)
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return result
(2)后序遍历
C++:
在这里插入代码片
Python:
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack = [root]
result = []
while stack:
node = stack.pop()
# 中结点先处理
result.append(node.val)
# 左孩子先入栈
if node.left:
stack.append(node.left)
# 右孩子后入栈
if node.right:
stack.append(node.right)
# 将最终的数组翻转
return result[::-1]
(3)中序遍历
中序对于先序和后序要复杂一点,因为先序的访问顺序和输出顺序是一致的,访问一个就可以输出,再丢弃。因为二叉树的代码都是从顶端开始访问的,但是中序是左-中-右,就意味着要先从顶部找到左边最低端,再开始从左向上输出,所以需要一个指针来帮助遍历结点。
C++:
在这里插入代码片
Python:
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack = [] # 不能提前将root结点加入stack中
result = []
cur = root
while cur or stack:
# 用来把自顶向左的访问顺序的路径存在stack中,栈顶就是最左结点
if cur:
stack.append(cur)
cur = cur.left
# 从最左结点开始处理输出
else:
cur = stack.pop()
result.append(cur.val)
# 取栈顶元素右结点
cur = cur.right
return result
3. 二叉树的层序遍历
(1)经典层序遍历
题目:给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
思路:需要借用一个辅助队列来实现,队列先进先出,符合一层一层遍历的逻辑。
笔记:C++中que.front()
函数返回队列的前端元素。
python中队列操作常采用from collections import deque
,deque为双端队列。
其中,append()
是从右端入队,popleft()
是从左端移除
C++:
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> que; //定义队列
if(root != nullptr) que.push(root); //根入队
vector<vector<int>> result; //结果为二维数组
while(!que.empty()){
int size = que.size();
// 内层数组:每一层的结点
vector<int> res;
// 用固定大小size,不要使用que.size(),因为que.size是不断变化的
for(int i = 0; i < size; i++){
// 队头写到结果里
TreeNode *node = que.front();
que.pop();
// 队头写到结果里
res.push_back(node->val);
// 再把他的左右孩子入队
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(res); //每层res再写入外层数组中
}
return result;
}
};
Python:
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
results = []
if root == None:
return results
from collections import deque
# root入队,只是一个根节点,不是整个序列!!!
que = deque([root])
# 每次pop出来一个节点,就把其子女入que,所以当子女都没子女了,就终结
while que:
size = len(que) #这里的size只是每层的结点数量,会更新
# 内层数组
result = []
for _ in range(size): #把这层个节点的子女都入队
# 弹出一个值作为node
node = que.popleft()
# node存入内层中
result.append(node.val)
# 把他的左右孩子入队
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
results.append(result)
return results
(2)从底向上层序遍历
题目:给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
输入:root = [3,9,20,null,null,15,7]
输出:[[15,7],[9,20],[3]]
思路:就是把经典层序遍历最后的result数组反转一下即可
笔记:
Python中reverse()
和reversed()
的区别:
reverse()仅限于list,返回值是None,结果可以直接print出来
a1=[1,2,3,4]
print(a1.reverse())
print(a1)
None
[4, 3, 2, 1]
reversed()可用于tuple, string, list 或 range,返回值是一个迭代器,结果需要通过列表、元组或者for循环输出
a1=[1,2,3,4]
print(reversed(a1))
print(list(reversed(a1)))
<list_reverseiterator object at 0x0000023F56ACD4C0>
[4, 3, 2, 1]
# 字符串
seqString = 'Runoob'
print(list(reversed(seqString)))
# 元组
seqTuple = ('R', 'u', 'n', 'o', 'o', 'b')
print(list(reversed(seqTuple)))
# range
seqRange = range(5, 9)
print(list(reversed(seqRange)))
# 列表
seqList = [1, 2, 4, 3, 5]
print(list(reversed(seqList)))
C++:
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
queue<TreeNode*> que; //定义队列
if(root != nullptr) que.push(root); //根入队
vector<vector<int>> result; //结果为二维数组
while(!que.empty()){
int size = que.size();
// 内层数组:每一层的结点
vector<int> res;
// 用固定大小size,不要使用que.size(),因为que.size是不断变化的
for(int i = 0; i < size; i++){
// 队头写到结果里
TreeNode *node = que.front();
que.pop();
// 队头写到结果里
res.push_back(node->val);
// 再把他的左右孩子入队
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(res); //每层res再写入外层数组中
}
// 反转数组
reverse(result.begin(), result.end());
return result;
}
};
Python:
class Solution:
def levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
results = []
if root == None:
return results
from collections import deque
# root入队
que = deque([root])
while que:
size = len(que)
# 内层数组
result = []
for _ in range(size):
# 弹出一个值作为node
node = que.popleft()
# node存入内层中
result.append(node.val)
# 把他的左右孩子入队
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
results.append(result)
results.reverse()
return results
(3)二叉树的右视图
题目:给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
输入: [1,2,3,null,5,null,4]
输出: [1,3,4]
思路:层序遍历的时候,判断是否遍历到单层的最后面的元素,如果是,就放进result数组中
C++:
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> res;
queue<TreeNode*> que;
if(root == NULL) return res;
que.push(root);
while(!que.empty()){
int size = que.size();
TreeNode* node = que.back();
res.push_back(node->val);
for(int i = 0; i < size; i++){
node = que.front();
que.pop();
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return res;
}
};
Python:
from collections import deque
class Solution:
def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
res = []
if not root:
return res
que = deque([root])
while que:
node = que[-1]
res.append(node.val)
for _ in range(len(que)):
node = que.popleft()
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
return res
(4)二叉树的层平均值
题目:给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。
输入:root = [3,9,20,null,null,15,7]
输出:[3.00000,14.50000,11.00000]
解释:第 0 层的平均值为 3,第 1 层的平均值为 14.5,第 2 层的平均值为 11 。
因此返回 [3, 14.5, 11] 。
思路:层序遍历的时候把一层求个总和在取一个均值。
C++:
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
vector<double> res;
queue<TreeNode*> que;
if(root == NULL) return res;
que.push(root);
while(!que.empty()){
double sum_ = 0;
int size = que.size();
for(int i = 0; i < size; i++){
TreeNode* node = que.front();
que.pop();
sum_ += node->val;
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
res.push_back(sum_/size);
}
return res;
}
};
Python:
class Solution:
def averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
res = []
if not root:
return res
from collections import deque
que = deque([root])
while que:
size = len(que)
sum_ = 0
for _ in range(size):
node = que.popleft()
sum_ += node.val
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
res.append(sum_/size)
return res
(5)N叉树的层序遍历
题目:给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。
输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:[[1],[2,3,4,5],[6,7,8,9,10],[11,12,13],[14]]
思路:左孩右孩变成children数组
笔记:Python:deque中extend()
函数表示将一个list的值全部入队。
C++:
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
queue<Node*> que;
vector<vector<int>> results;
if(root == nullptr) return results;
que.push(root);
while(!que.empty()){
int size = que.size();
vector<int> res;
for(int i = 0; i < size; i++){
Node* node = que.front();
que.pop();
res.push_back(node->val);
for(int i = 0; i < node->children.size(); i++){
if(node->children[i]) que.push(node->children[i]);
}
}
results.push_back(res);
}
return results;
}
};
Python:
class Solution:
def levelOrder(self, root: 'Node') -> List[List[int]]:
results = []
if not root:
return results
from collections import deque
que = deque([root])
while que:
size = len(que)
res = []
for _ in range(size):
node = que.popleft()
res.append(node.val)
if node.children:
que.extend(node.children)
results.append(res)
return results
(6)在每个树行中找最大值
题目:给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。
输入: root = [1,3,2,5,3,null,9]
输出: [1,3,9]
思路:每层for循环中每次都比较最大值
笔记:
C++:
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
vector<int> res;
queue<TreeNode*> que;
if(root == NULL) return res;
que.push(root);
while (!que.empty()){
int size = que.size();
int max_ = INT_MIN;
for(int i = 0; i < size; i++){
TreeNode* node = que.front();
que.pop();
max_ = node->val > max_ ? node->val : max_;
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
res.push_back(max_);
}
return res;
}
};
Python:
class Solution:
def largestValues(self, root: Optional[TreeNode]) -> List[int]:
res = []
if root == None:
return res
from collections import deque
que = deque([root])
while que:
max_ = -inf
for _ in range(len(que)):
node = que.popleft()
max_ = max(max_, node.val)
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
res.append(max_)
return res
(7)填充每个节点的下一个右侧节点指针
题目:给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
输入:root = [1,2,3,4,5,6,7]
输出:[1,#,2,3,#,4,5,6,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化的输出按层序遍历排列,同一层节点由 next 指针连接,'#' 标志着每一层的结束。
思路:
笔记:完美二叉树即满二叉树,不是完全二叉树。
C++:
class Solution {
public:
Node* connect(Node* root) {
if(root == nullptr) return root;
queue<Node*> que;
que.push(root);
while (!que.empty()){
int size = que.size();
for(int i = 0; i < size; i++){
Node* node = que.front();
que.pop();
if(i < size - 1){
node->next = que.front();
}
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return root;
}
};
Python:
迭代法
def connect(self, root: 'Node') -> 'Node':
if not root:
return
if root.left:
root.left.next = root.right
if root.next:
root.right.next = root.next.left
self.connect(root.left)
self.connect(root.right)
return root
层次遍历法
class Solution:
def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
if not root:
return root
from collections import deque
que = deque([root])
while que:
size = len(que)
for i in range(size):
node = que.popleft()
# 把这层中除了最右边的那个节点,其他节点全部next连起来
# 放在第一个if,因为后面que会加孩子,就不只是这层的元素了
if i < size - 1:
node.next = que[0]
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
return root
(8)二叉树的最大深度
题目:给定一个二叉树,找出其最大深度
思路:return len(results)
即可。
C++:
class Solution {
public:
int maxDepth(TreeNode* root) {
vector<vector<int>> results;
queue<TreeNode*> que;
if(root == NULL) return 0;
que.push(root);
while (!que.empty()){
vector<int> res;
int size = que.size();
for(int i = 0; i < size; i++){
TreeNode* node = que.front();
que.pop();
res.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
results.push_back(res);
}
return results.size();
}
};
Python:
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
results = []
if not root:
return 0
from collections import deque
que = deque([root])
while que:
res = []
for _ in range(len(que)):
node = que.popleft()
res.append(node.val)
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
results.append(res)
return len(results)
(9)二叉树的最小深度
题目:给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
输入:root = [3,9,20,null,null,15,7]
输出:2
思路:和最大深度一样,只是判定条件为:左右孩都为空。
笔记:
C++:
class Solution {
public:
int minDepth(TreeNode* root) {
if (root == NULL) return 0;
int depth = 0;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()) {
int size = que.size();
depth++; // 记录最小深度
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
if (!node->left && !node->right) { // 当左右孩子都为空的时候,说明是最低点的一层了,退出
return depth;
}
}
}
return depth;
}
};
Python:
- 迭代法(层序遍历)
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
if root == None:
return 0
from collections import deque
que = deque([root])
depth = 0
while que:
depth += 1
for _ in range(len(que)):
node = que.popleft()
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
if node.left == None and node.right == None:
return depth
- 递归法
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
if not root.left and not root.right:
return 1
min_depth = inf
if root.left:
min_depth = min(self.minDepth(root.left), min_depth)
if root.right:
min_depth = min(self.minDepth(root.right), min_depth)
return min_depth + 1