树数据结构允许以层级形式存储数据。根据存储数据的方式,有多种树类型,如二叉树。
和它的近亲二叉搜索树一样,它也是最流行的树数据结构之一。因此,你会看到很多相关的有趣问题。例如,如何遍历树、计算节点数量、找出深度,以及检查是否平衡。
解决二叉树问题的关键在于深厚的理论知识,如二叉树的大小或深度、什么是叶节点、什么是节点,以及了解流行的遍历算法。
1.二叉树的遍历
树的节点定义
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
<1>前序
用一个栈,压栈前先打印
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
Stack<TreeNode> st = new Stack<TreeNode>();
TreeNode node = root;
while(node!=null||st.size()>0) {
while(node!=null) {
res.add(node.val);
st.push(node);
node=node.left;
}
if(!st.empty()) {
node=st.pop();
node=node.right;
}
}
return res;
}
<2>中序
一个栈,出栈后打印
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
Stack<TreeNode> st = new Stack<TreeNode>();
TreeNode node = root;
while(node!=null||st.size()>0) {
while(node!=null) {
st.push(node);
node=node.left;
}
if(!st.empty()) {
node=st.pop();
res.add(node.val);
node=node.right;
}
}
return res;
}
<3>后序
两个栈,一个栈存储根、右节点,一个回退取左节点。
最后输出逆序的根右左,即为左右根。
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
Stack<TreeNode> st = new Stack<TreeNode>();
Stack<TreeNode> out = new Stack<TreeNode>();
TreeNode node = root;
while(node!=null||st.size()>0){
if(node!=null){
st.push(node);
out.push(node);
node=node.right;
}else{
node = st.pop();
node=node.left;
}
}
while(!out.empty()){
res.add(out.pop().val);
}
return res;
}
<4>层序
队列实现
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new LinkedList<List<Integer>>();
Queue<TreeNode> qu = new LinkedList<TreeNode>();
if(root==null) return res;
qu.add(root);
while(qu.size()>0){
int size = qu.size();
List<Integer> temp = new LinkedList<>();
while(size-->0){
TreeNode node = qu.poll();
temp.add(node.val);
if(node.left!=null)
qu.add(node.left);
if(node.right!=null)
qu.add(node.right);
}
res.add(temp);
}
return res;
}
public class Solution {
public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
Queue<TreeNode> qu = new LinkedList<>();
ArrayList<Integer> res = new ArrayList<>();
if(root == null)
return res;
qu.offer(root);
while(qu.size()!=0){
TreeNode cur = qu.poll();
res.add(cur.val);
if(cur.left!=null)
qu.offer(cur.left);
if(cur.right!=null)
qu.offer(cur.right);
}
return res;
}
}
23.二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
思路:二叉搜索树的左分支比根小,右分支比根大。
如果是后序遍历,根节点在最后,则数组前部分为比根小,后部分比根大。
从后往前遍历,是否都满足该规则,不满足则false。
public class Solution {
public boolean VerifySquenceOfBST(int [] sequence) {
if(sequence==null||sequence.length<=0)
return false;
int len = sequence.length;
while(--len>0){
int i=0;
while(sequence[i]<sequence[len])
i++;
while(sequence[i]>sequence[len])
i++;
if(i!=len)
return false;
}
return true;
}
}
2.二叉树反转左右节点
public static void swapNode(Node root) {
if(root==null)
return ;
Node tmp = root.getLeftNode();
root.setLeftNode(root.getRightNode());
root.setRightNode(tmp);
swapNode(root.getLeftNode());
swapNode(root.getRightNode());
}
二叉搜索树中第K小的元素
给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。
说明:
你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。
思路:二叉搜索树的中序遍历有序;
因此直接中序遍历即可;
public int kthSmallest(TreeNode root, int k) {
Stack<TreeNode> st = new Stack<TreeNode>();
TreeNode node = root;
int tmp = 0;
while (node != null || st.size() > 0) {
while (node != null) {
st.push(node);
node = node.left;
}
if (!st.empty()) {
node = st.pop();
tmp = node.val;
k--;
if (k == 0)
return tmp;
node = node.right;
}
}
return tmp;
}