文章目录
一、二叉树的前序遍历
1、递归遍历
递归遍历的三个要素
- 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
- 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
- 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程
前序遍历的递归算法
public void PreOrder(TreeNode root, List<Integer> result){ // 1、参数和返回值
if(root==null){ // 2、终止条件
return;
}
// 3、单层逻辑
result.add(root.val); // 中
PreOrder(root.left, result); // 左
PreOrder(root.right, result); // 右
}
2、非递归遍历
前序遍历的非递归有两种写法
1、前序遍历是中左右,每次先处理的是中间节点,那么先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。 这种做法和后序的非递归是一种方法
public List<Integer> preorderTraversal(TreeNode root) {
// 第一种做法:基于 中,右, 左的进栈顺序
List<Integer> list = new LinkedList<>();
if(root==null){
return list;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode cur = stack.pop();
list.add(cur.val);
if(cur.right!=null){
stack.push(cur.right);
}
if(cur.left!=null){
stack.push(cur.left);
}
}
return list;
}
2、需要树的遍历来帮助访问节点,栈则用来处理节点上的元素。这种做法和中序遍历的非递归方法是一样的
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new LinkedList<>();
if(root==null){
return list;
}
Stack<TreeNode> stack = new Stack<>();
while(root!=null||!stack.isEmpty()){
if(root!=null){
list.add(root.val);
stack.push(root);
root = root.left;
}else{
TreeNode node = stack.pop();
root = node.right;
}
}
return list;
}
3、既不用递归也不用栈遍历
要想实现这样的算法得利用线索二叉树的思想
二、二叉树的中序遍历
1、递归遍历
public void MiddleOrder(TreeNode root, List<Integer> result){ // 1、参数和返回值
if(root==null){ // 2、终止条件
return;
}
// 3、单层逻辑
MiddleOrder(root.left, result); // 左
result.add(root.val); // 中
MiddleOrder(root.right, result); // 右
}
2、非递归遍历
中序遍历的非递归方式和前序非递归遍历的第二种方式是一样的
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new LinkedList<>();
if(root==null){
return list;
}
Stack<TreeNode> stack = new Stack<>();
while(root!=null||!stack.isEmpty()){
if(root!=null){
stack.push(root);
root = root.left;
}else{
TreeNode node = stack.pop();
list.add(node.val);
root = node.right;
}
}
return list;
}
三、二叉树的后序遍历
1、递归遍历
后序遍历的递归算法
public void PostOrder(TreeNode root, List<Integer> result){ // 1、参数和返回值
if(root==null){ // 2、终止条件
return;
}
// 3、单层逻辑
PreOrder(root.left, result); // 左
PreOrder(root.right, result); // 右
result.add(root.val); // 中
}
2、非递归遍历
后序遍历的非递归方式是和前序非递归是一样的。
在前序非递归遍历中,进栈的顺序是 中—>右---->左,这样在每一轮的判断中,我们就可以先出栈左结点,并将其值加入到List列表中,最终我们得到的了中—>左---->右的前序遍历。
那么在后序遍历中,我们如何得到左---->右—>中的后序遍历了?
也就是说我们按照中—>左---->右的进栈顺序,得到中—>右---->左,最后进行反转,就可以得到左---->右—>中的后序遍历了。
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new LinkedList<>();
if(root==null){
return list;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop(); // 中
list.add(node.val);
if(node.left!=null){
stack.push(node.left); // 左
}
if(node.right!=null){
stack.push(node.right); // 右
}
}
Collections.reverse(list); // 反转
return list;
}
四、二叉树的层序遍历
BFS我们需要用队列去保存每层的结点,另外一个注意点就是,如何去保证每次只遍历本层的结点了?那就需要在队列中加入下一层结点之前,我们需要统计本层的结点,也就是计算队列的大小,int size = queue.size();
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ans = new LinkedList<>();
if(root==null){
return ans;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
int size = queue.size();
List<Integer> list = new LinkedList<>();
for(int i=0;i<size;i++){
TreeNode node = queue.remove();
list.add(node.val);
if(node.left!=null){
queue.add(node.left);
}
if(node.right!=null){
queue.add(node.right);
}
}
ans.add(list);
}
return ans;
}