1 二叉树的前中后序递归实现
树的前中后序的遍历这个是很常见的问题,其递归做法相对简单,呜呜,但是刷题的时候好像都要用非递归
//前序遍历
List<Integer> preList = new ArrayList<Integer>();
public List<Integer> preOrder(TreeNode root){
if(root == null){
return null;
}
preList.add(root.val);
preOrder(root.left);
preOrder(root.right);
return preList;
}
//中序遍历
List<Integer> inList = new ArrayList<Integer>();
public List<Integer> inOrder(TreeNode root) {
if(root == null){
return null;
}
inOrder(root.left);
inList.add(root.val);
inOrder(root.right);
return inList;
}
//后序遍历
List<Integer> postList = new ArrayList<Integer>();
public List<Integer> postOrder(TreeNode root){
if(root == null){
return null;
}
postOrder(root.left);
postOrder(root.right);
postList.ass(root.val);
return postList;
}
从上面的代码中可以看到,树的前中后序遍历代码结构基本相同,差距只要在何时输出根值,前序遍历一遍历到节点时,先输出根值,中序是遍历完左子节点,后序是最后才输出
2 二叉树的前序遍历非递归实现
这个对应到--------非递归的前序遍历:(LeetCode 144)
在迭代法中,我们使用栈来实现。由于出栈顺序和入栈顺序相反,所以每次添加节点的时候先添加右节点,再添加左节点。这样在下一轮访问子树的时候,就会先访问左子树,再访问右子树
//根据前序遍历的特点,我们很容易将其与栈的特点相结合
public List<Integer> preorderTraversal(TreeNode root){
List<Integer> lists = new ArrayList<>();
if(root == null){
return lists;
}
Stack<TreeNode> stack = new Stack<>();
//根节点先入栈
stack.push(root);
TreeNode temp = null;
while(!stack.isEmpty()){
temp = stack.pop();
lists.add(temp.val);
//这里注意,要先压入右子结点,再压入左节点。因为栈是先进后出
if(temp.right != null){
stack.push(temp.right);
}
if(temp.left != null){
stack.push(temp.left);
}
}
return lists;
}
3 二叉树的中序遍历非递归实现
这个对应到--------非递归的中序遍历:(LeetCode 94)
中序遍历的迭代法要稍微复杂一点,因为最先遇到的根节点不是最先访问的,我们需要先访问左子树,再回退到根节点,再访问根节点的右子树,这里的一个难点是从左子树回退到根节点的操作,虽然可以用栈来实现回退,但是要注意在出栈时保存根节点的引用,因为我们还需要通过根节点来访问右子树:
//中序遍历的思路:先找到最左的子树,然后返回其父节点,然后遍历右子树
//特点也是与栈这个数据结构比较吻合
public List<Integer> inorderTraversal(TreeNode root){
Stack<TreeNode> stack = new Stack<>();
TreeNode node = root, temp = null;
List<Integer> lists = new ArrayList<>();
if(root == null){
return lists;
}
//判断条件:所有栈为空,且节点指向为空,即所有节点已经完成遍历
while(!stack.isEmpty() || node != null){
//向左搜索,寻找最左的节点,即中序遍历的第一个节点
while(node != null){
stack.add(node);
node = node.left;
}
//对每一个节点进行判断
if(!stack.empty()){
//获取当前节点
temp = stack.pop();
//遍历该节点
lists.add(temp.val);
//如果该节点为内部节点,则按中序遍历的顺序,遍历奇右子节点
node = temp.right;
}
}
return lists;
}
4 二叉树的后序遍历非递归实现
这个对应到------非递归的后序遍历:(LeetCode 145)
与中序遍历不同的是,后序遍历在访问完左子树向上回退到根节点的时候不是立马访问根节点的,而是得先去访问右子树,访问完右子树后在回退到根节点,因此,在迭代过程中要复杂一点:
后序遍历的方法:先左子树,后右子树,再最后根节点
如果反过来,顺序就变成了:先根节点,后右子树,再左子树,和先序遍历有点像
因此,后序遍历可以变为:先遍历根节点,后遍历右子树,再遍历左子树结果的逆序
//后序遍历的方法:先左子树,后右子树,再最后根节点
//如果反过来,顺序就变成了:先根节点,后右子树,再左子树,和先序遍历有点像
//因此,后序遍历可以变为:先遍历根节点,后遍历右子树,再遍历左子树结果的逆序
public List<Integer> postorderTraversal(TreeNode root){
LinkedList<Integer> lists = new LinkedList<>();
if(root == null){
return lists;
}
Stack<TreeNode> stack = new Stack<>();
//根节点压入
stack.push(root);
TreeNode temp = null;
while(!stack.isEmpty()){
temp = stack.pop();
lists.addFirst(temp.val);
//先压左节点,再压入右节点。因为是栈,先入后出,所以先访问的是右,后访问的是左
if(temp.left != null){
stack.push(temp.left);
}
if(temp.right != null){
stack.push(temp.right);
}
}
return lists;
}
5 二叉树的层次遍历非递归实现
这个对应到------层序遍历:(LeetCode 102、103、107)
层序遍历,就是按照每一层的顺序,一层一层的访问。
/*层序遍历,就是按照每一层的顺序,一层一层的访问*/
//根据层次遍历的特点,我们很容易想到应该使用队列
//利用广度优先遍历的方式,进行遍历
public List<List<Integer>> levelOrder(TreeNode root){
if(root == null){
return new ArrayList<>();
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
List<List<Integer>> lists = new ArrayList<>();
List<Integer> arrays = new ArrayList<>();
TreeNode temp = null;
while(!queue.isEmpty()){
int n = queue.size();
//这里通过读取队列的元素,获取这一层有多少个元素
for(int i = 0; i < n; i++){
temp = queue.poll();
arrays.add(temp.val);
if(temp.left != null){
queue.add(temp.left);
}
if(temp.right != null){
queue.add(temp.right);
}
}
//将每一层的数据都放入链表中
lists.add(new ArrayList<>(arrays));
arrays.clear();
}
return lists;
}
参考链接
https://blog.csdn.net/Applying/article/details/84982712
https://blog.csdn.net/Demorngel/article/details/88550486