进入到二叉树章节了,今天学习了前中后序的递归遍历及迭代遍历。先了解三种遍历的规则
前序遍历:中左右
中序遍历:左中右
后序遍历:左右中
一、递归遍历
大家递归应该很了解了。写一个递归要遵循三步走战略,第一确定参数和返回值,第二确定终止条件,第三确定单层递归的逻辑。递归感悟:递归最喜欢处理的就是问题能处理成无数个子问题的题型(这句话,很重要,大家写题感悟一下)
// 前序遍历·递归·LC144_二叉树的前序遍历
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<Integer>();
preorder(root, result);
return result;
}
public void preorder(TreeNode root, List<Integer> result) {
if (root == null) {
return;
}
result.add(root.val);
preorder(root.left, result);
preorder(root.right, result);
}
}
// 中序遍历·递归·LC94_二叉树的中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
inorder(root, res);
return res;
}
void inorder(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
inorder(root.left, list);
list.add(root.val); // 注意这一句
inorder(root.right, list);
}
}
// 后序遍历·递归·LC145_二叉树的后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
postorder(root, res);
return res;
}
void postorder(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
postorder(root.left, list);
postorder(root.right, list);
list.add(root.val); // 注意这一句
}
}
二、迭代遍历
递归是栈底层实现的,基本上递归的问题都可以用栈来解决。这次就放前序和中序,后序和前序思路差不多,只不过要进行代码调整位置和反转
前序遍历:
思路:先放入根节点,由于栈的先进后出的特性,弹出这个节点加入结果集,先放右节点再放左节点,然后循环往复就行了,大家模拟一下就知道思路了。
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result=new ArrayList<>();
if (root == null){
return result;
}
Deque<TreeNode> record=new LinkedList<>();
record.push(root);
while(!record.isEmpty()){
TreeNode temp=record.pop();
result.add(temp.val);
if(temp.right!=null)record.push(temp.right);
if(temp.left!=null)record.push(temp.left);
}
return result;
}
}
中序遍历 :
思路:这道题由于遍历二叉树的顺序不是要处理的顺序,最好用cur另外存储遍历顺序,然后栈记录节点,方便cur进行操作
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result=new ArrayList<>();
if(root==null)return result;
TreeNode cur=root;
Deque<TreeNode> stack=new LinkedList<>();
while(cur!=null||!stack.isEmpty()){
if(cur!=null){
stack.push(cur);
cur=cur.left;
}else{
cur=stack.pop();
result.add(cur.val);
cur=cur.right;
}
}
return result;
}
}
后序遍历:
其实就是前序遍历改过来的,前序遍历是中左右,把左右节点的顺序换一下,就是中右左,再反转,就是左右中,就是后序遍历的方式
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
result.add(node.val);
if (node.left != null){
stack.push(node.left);
}
if (node.right != null){
stack.push(node.right);
}
}
Collections.reverse(result);
return result;
}
}
三、层序遍历
层序遍历就是一层一层遍历,一层的遍历规则是从左往右。
思路:这道题要用队列解,先放入根节点,记录当前层的size,然后poll出头元素放入结果中,然后左右节点不为空的话就入队列,这样持续到size<=0,然后进行下一层遍历,持续这样,直到队列为空。这道题要注意的是temp一定要在while新创建,而不能在一层遍历结束后清空,因为链表添加的是地址,当temp改变的时候,链表存的元素也会改变,造成结果错误
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if(root==null)return new ArrayList<>();
List<List<Integer>> result=new ArrayList<>();
Deque<TreeNode> record=new LinkedList<>();
int size=1;
record.offer(root);
while(!record.isEmpty()){
List<Integer> temp=new ArrayList<>();
while(size-->0){
TreeNode cur=record.poll();
if(cur.left!=null) {
record.offer(cur.left);
}
if(cur.right!=null){
record.offer(cur.right);
}
temp.add(cur.val);
}
result.add(temp);
size=record.size();
}
return result;
}
}