栈的推荐写法:
Deque<TreeNode> stack = new LinkedList<>();
JDK文档:虽然 Deque 实现没有严格要求禁止插入 null 元素,但建议最好这样做。建议任何事实上允许 null 元素的 Deque 实现用户最好不 要利用插入 null 的功能。这是因为各种方法会将 null 用作特殊的返回值来指示双端队列为空。
队列的推荐写法:Queue<TreeNode> queue = new LinkedList<>();
优先队列(底层是堆实现的)的推荐写法:
小根堆:PriorityQueue<Integer> queue = new PriorityQueue<>((v1, v2) -> v1 - v2;
java默认使用最小堆,实现大根堆需要重写一下比较器。
大根堆:PriorityQueue<Integer> queue = new PriorityQueue<>((v1, v2) -> v2 - v1;
为了不改变根节点:TreeNode cur = root;
非递归版本的框架:需要一个栈 s 来树中的结点,一个 list 来存储结果集。
整体框架
// 一个栈和一个list
List<Integer> res = new ArrayList<>();
Deque<TreeNode> s = new ArrayDeque<>();
// 为了不改变根节点
TreeNode cur = root;
while (cur != null || !s.isEmpty()) {
if(cur != null){
// 处理结点
}else {
cur = s.pop();
// 处理结点
}
}
先序遍历
// 先序
while (cur != null || !s.isEmpty()) {
if(cur != null){
s.push(cur); // 根
res.add(cur.val);
cur = cur.left; // 左
}else {
cur = s.pop();
cur = cur.right; // 右
}
}
深度优先遍历
迭代:先往栈中压入右节点,再压左节点,这样出栈就是先左节点后右节点了。
public class Solution {
public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
ArrayList<Integer> res=new ArrayList<Integer>();
if(root==null) return lists;
Deque<TreeNode> stack = new ArrayDeque<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode cur=stack.pop();
if(cur.right!=null)
stack.push(cur.right);
if(tree.left!=null)
stack.push(cur.left);
res.add(cur.val);
}
return res;
}
}
public void depthOrderTraversalWithRecursive() {
depthTraversal(root);
}
private void depthTraversal(TreeNode node) {
if (node!= null) {
System.out.print(node.value + " ");
depthTraversal(node.left);
depthTraversal(node.right);
}
}
中序遍历
// 中序
while (cur != null || !s.isEmpty()) {
if(cur != null){
s.push(cur);
cur = cur.left; // 左
}else {
cur = s.pop();
res.add(cur.val); // 根
cur = cur.right; // 右
}
}
后序遍历
// 后序 左-->右-->根 将前序遍历调整一下 根-->右-->左
// 然后结果存放到栈里进行倒序, 之后再遍历结果栈就可以输出后序遍历了
while (cur != null || !s.isEmpty()) {
if(cur != null){
s.push(cur);
resStack.push(cur); // 根
cur = cur.right; // 右
}else {
cur = s.pop();
cur = cur.left; // 左
}
}
// 遍历结果栈
while(!resStack.isEmpty()){
res.add(resStack.pop().val);
}
层次遍历
分两种情况,比如下面的树,1.返回一位列表 [3,9,20,15,7]
2.另一种情况是返回二维列表 [[3],[9,20],[15,7]]
// 情况1 全部结点加入队列
class Solution {
public int[] levelOrder(TreeNode root) {
List<Integer> res = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
if(root == null) return new int[]{};
queue.add(root);
while(!queue.isEmpty()){
TreeNode node = queue.poll();
res.add(node.val);
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
}
int[] ans = new int[res.size()];
for(int i = 0; i < res.size(); i++){
ans[i] = res.get(i);
}
return ans;
}
}
// 情况2 全部结点加入队列
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
if(root == null) return res;
queue.offer(root);
while(!queue.isEmpty()){
// 临时list
List<Integer> temp = new ArrayList<>();
int size = queue.size();
// 将队列中的元素全部出队
for(int i = 0; i < size; i++){
TreeNode node = queue.poll();
temp.add(node.val);
// 出队后将其左右孩子加入队列
if(node.left != null) queue.offer(node.left);
if(node.right != null) queue.offer(node.right);
}
res.add(temp);
}
return res;
}
}
public class TreeNode {
int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int x) {
val = x;
}
public TreeNode(int x, TreeNode l, TreeNode r) {
val = x;
this.left = l;
this.right = r;
}
}
class Solution {
public List<Integer> preorderTraversal1(TreeNode root) {
List<Integer> res = new ArrayList<>();
preorder(root, res);
return res;
}
// 递归版本
public void preorder(TreeNode root, List<Integer> res) {
if (root == null) return;
res.add(root.val);
preorder(root.left, res);
preorder(root.right, res);
}
// 迭代版本
public List<Integer> preorderTraversal2(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> s = new ArrayDeque<>();
// 为了不改变根节点
TreeNode cur = root;
while (cur != null || !s.isEmpty()) {
if(cur != null){
s.push(cur);
res.add(cur.val);
cur = cur.left;
}else {
cur = s.pop();
cur = cur.right;
}
}
return res;
}
public List<Integer> inorderTraversal1(TreeNode root) {
List<Integer> res = new ArrayList<>();
preorder(root, res);
return res;
}
// 递归版本
public void inorder(TreeNode root, List<Integer> res) {
if (root == null) return;
inorder(root.left, res);
res.add(root.val);
inorder(root.right, res);
}
public List<Integer> inorderTraversal2(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> s = new ArrayDeque<>();
TreeNode cur = root;
while (cur != null || !s.isEmpty()) {
if (cur != null) {
s.push(cur);
cur = cur.left;
} else {
cur = s.pop();
res.add(cur.val);
cur = cur.right;
}
}
return res;
}
public List<Integer> postorderTraversal1(TreeNode root) {
List<Integer> res = new ArrayList<>();
postorder(root, res);
return res;
}
public void postorder(TreeNode root, List<Integer> res) {
if(root == null){
return;
}
postorder(root.left, res);
postorder(root.right, res);
res.add(root.val);
}
// 前序遍历顺序为:根 -> 左 -> 右
// 后序遍历顺序为:左 -> 右 -> 根
// 所以, 我们可以把前序遍历的稍作修改: 根 -> 右 -> 左,
// 然后结果存放到栈里进行倒序, 之后再遍历结果栈就可以输出后序遍历了
public List<Integer> postorderTraversal2(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> s = new ArrayDeque<>();
Deque<TreeNode> resStack = new ArrayDeque<>();
TreeNode cur = root;
while (cur != null || !s.isEmpty()){
if (cur != null){
resStack.push(cur);
s.push(cur);
cur = cur.right;
}else {
cur = s.pop();
cur = cur.left;
}
}
while (!resStack.isEmpty()){
res.add(resStack.pop().val);
}
return res;
}
}