1. 对于二叉搜索树的遍历的操作中使用典型的方法是中序遍历,中序遍历对于一棵树的遍历是先遍历左子树,然后根,最右子树
并且中序遍历有递归形式有非递归形式,我们知道一棵树是递归定义的,所以对于树的遍历操作中当然可以使用递归的方法来进行遍历,而且使用递归的方式来进行遍历的话代码很简洁
而且递归使用的是隐式的栈,所以我们可以自己模仿递归的过程借助栈来实现非递归形式的递归,可以自己画出一棵二叉搜索树来模仿递归的过程来写出代码
2. 我们可以利用中序遍历可以解决很多关于二叉搜索树的问题,其中最常见的使用情况如下:
① 使用中序遍历来判断一棵树是否是二叉搜索树
a:递归形式的话一我们可以对树从根节点进行遍历,把中序遍历的结果放入到一个数组中最后遍历数组两两比较大小看是否满足条件
private void inorder(TreeNode<Integer> node, ArrayList<Integer> list) {
if (node == null)
return;
if (node.left != null) {
inorder(node.left, list);
}
list.add(node.val);
if (node.right != null) {
inorder(node.right, list);
}
}
//遍历列表,前后两两比较,如果逆序,返回false
private boolean checkOrdered(ArrayList<Integer> list) {
for (int i = 0; i < list.size() - 2; i++) {
if (list.get(i) > list.get(i + 1))
return false;
}
return true;
}
b:二是我们可以对中间左子树调用完成返回之后来处理根节点与子树之间的大小关系返回一个布尔值
每一层调用返回之后通过比较全局变量的值与当前节点的值来返回一个布尔值,而这个布尔值就是每一层调用之后函数返回的布尔值,所以我们需要对函数返回的布尔值进行判断看是否为true
public boolean checkBST(TreeNode<Integer> root) {
if (root == null)
return true;
//检查左子树,如果左子非bst立即返回false
boolean leftIsBST = checkBST(root.left);
if (!leftIsBST)
return false;
//根的值小于等于左子树的最大值,返回false
if (root.val <= preValue) {
return false;
}
//更新最后访问的值,检查右子树
preValue = root.val;
return checkBST(root.right);
}
② 解决树节点定义中不带有parent指针的后继的求解
a:求解后继也是可以使用中序遍历的递归形式,也可以像上面一样使用一个全局变量来进行记录之前节点的值,每一层调用都更新全局变量的值与当前退回来的节点的值进行比较看是否相等,当相等的时候说明找到了后继这个时候需要进行return即可
public class Main {
public static void main(String[] args) {
TreeNode<Integer> root = new TreeNode<Integer>(10);
TreeNode<Integer> l = new TreeNode<Integer>(7);
TreeNode<Integer> r = new TreeNode<Integer>(14);
TreeNode<Integer> ll = new TreeNode<Integer>(1);
TreeNode<Integer> lr = new TreeNode<Integer>(9);
TreeNode<Integer> rl = new TreeNode<Integer>(13);
TreeNode<Integer> rll = new TreeNode<Integer>(11);
root.left = l;
root.right = r;
l.left = ll;
l.right = lr;
r.left = rl;
rl.left = rll;
//使用中序遍历来记录退回来节点的值
inOrder(root, 1);
System.out.println(successor);
}
static int preValue = Integer.MIN_VALUE;
static int successor = -1;
private static void inOrder(TreeNode<Integer> node, int p) {
if(node == null) return;
inOrder(node.left, p);
if(preValue == p){
if(successor != -1){
return;
}
successor = node.val;
return;
}
preValue = node.val;
inOrder(node.right, p);
}
}
② 使用中序遍历的非递归形式弹出栈的顺序就是中序遍历的顺序,只需要一个全局变量来记录当前弹出的节点的值与目标值是否相等如果相等那么栈弹出来的下一个元素就是后继了
import java.util.Stack;
public class Main {
public static void main(String[] args) {
TreeNode<Integer> root = new TreeNode<Integer>(10);
TreeNode<Integer> l = new TreeNode<Integer>(7);
TreeNode<Integer> r = new TreeNode<Integer>(14);
TreeNode<Integer> ll = new TreeNode<Integer>(1);
TreeNode<Integer> lr = new TreeNode<Integer>(9);
TreeNode<Integer> rl = new TreeNode<Integer>(13);
TreeNode<Integer> rll = new TreeNode<Integer>(11);
root.left = l;
root.right = r;
l.left = ll;
l.right = lr;
r.left = rl;
rl.left = rll;
System.out.println(findSuccessor(root, 14));
}
private static int findSuccessor(TreeNode<Integer> root, int p) {
if(root == null) return -1;
//中序遍历的迭代形式
TreeNode<Integer> c = root;
boolean isFound = false;
Stack<TreeNode<Integer>> stack = new Stack<TreeNode<Integer>>();
while(c != null || !stack.isEmpty()){
while(c != null){
stack.push(c);
c = c.left;
}
if(!stack.isEmpty()){
TreeNode<Integer> poll = stack.pop();
if(isFound){
return poll.val;
}
//栈中弹出来的元素就是中序遍历的顺序
if(poll.val == p){
isFound = true;
}
c = poll.right;
}
}
return -1;
}
}