Sword33——二叉搜索树的后序遍历序列
方法1——递归
- 思路:树的大部分问题都可以使用递归解决。
- 首先确定当前树的根节点即为右边界j对应的数字
- 使用一个下标指针从左往右遍历
- 找到第一个比根节点大的值,即为右子树的第一个节点mid下标
- 接着从左往右遍历,判断其右子树节点是否全部大于根节点
- 当右子树节点部分出现不满足情况,则指针下标无法到右边界j,即返回false
- 否则则继续对其左子树和右子树递归,左右子树分界即为找到的右子树第一个节点mid下标
- 特殊情况与临界分析:无
- 终止条件:无
- 步骤:
- 开启递归
- 递归方法
- 参数:后序遍历数组、构造当前树的左右边界
- 终止条件:当左边界left大于等于右边界right时(似乎最多为等于,考虑到数组为空情况,将会出现left大于right情况),证明此时符合返回true
- (明确右边界right对应即为当前树的根节点,因为后序遍历为左-右-根)
- 定义指针下标,从左边界left开始
- 循环条件:从左边界left向右遍历,对应值小于右边界right对应根节点的值
- while循环
- 指针下标右移
- 记录while循环退出时第一个大于根节点的值下标mid,也就是右子树的第一个节点,即当前树左右子树的分隔点
- 循环条件:从mid开始继续向右遍历,对应值大于右边界right对应根节点的值
- while循环
- 指针下标右移
- 判断指针下标是否已达到右边界right,未到则代表右子树中存在比根节点小的节点,即不符合条件,返回false(可与最后一步合并)
- 继续对左右子树依次进行递归判断
- 左子树:左边界为left,右边界为mid - 1
- 右子树:左边界为mid,右边界为right - 1
public boolean verifyPostorder(int[] postorder) {
// 开启递归
return recur(postorder, 0, postorder.length - 1);
}
// 递归方法
private boolean recur(int[] postorder, int left, int right) {
// 递归终止条件
if (left >= right) {
return true;
}
// 定义指针下标
int point = left;
// while循环
while (postorder[point] < postorder[right]) {
// 指针下标后移
point++;
}
// 记录当前右子树的第一个节点下标
int mid = point;
// while循环
while (postorder[point] > postorder[right]) {
// 指针下标后移
point++;
}
// 当指针下标未达到右边界,直接返回不符合
// 继续对左右子树递归
return (point == right) && recur(postorder, left, mid - 1) && recur(postorder, mid, right - 1);
}
方法2——辅助栈
注意:此方法晦涩难懂,且时间耗费更长,有需要了解即可
- 思路:后序遍历为左-右-根,其逆序之后顺序为根-右-左。
- 假设当前树是以Integer.MAX_VALUE为根节点的左子树(为了符合左子树节点小于根节点,首先设置root为Integer最大值),判断数组中元素(即左子树节点)应该均小于根节点root
- 首先将当前树的根节点和右子树节点入栈,即只留下左子树节点
- 当遍历到左子树节点,则证明当前树的右子树部分是符合的,弹出栈中所有元素(栈底最后一个元素才为当前树的根节点)重新设置root节点,重新开始上述步骤即可
- 特殊情况与临界分析:
- 终止条件:
- 步骤:
- 定义辅助栈,便于存储节点
- 定义根节点
- for循环遍历数组
- 确定当前元素是否符合二叉树定义,即左子树节点比根节点要小
- while循环判断栈是否非空,且栈顶元素大于当前元素,符合即代表此时已遍历到左子树的第一个元素,出栈的栈底元素即为左子树的根节点
- 将当前元素压入栈中
- 如果在for循环中都符合二叉树定义,则最后返回true
public boolean verifyPostorder(int[] postorder) {
// 定义辅助栈
Deque<Integer> stack = new LinkedList<>();
// 定义根节点
int root = Integer.MAX_VALUE;
// for循环
for (int i = postorder.length - 1; i >= 0; i--) {
// 确定左子树节点比根节点要小
if (postorder[i] > root) {
return false;
}
// while循环找到栈顶元素
while (!stack.isEmpty() && stack.peek() > postorder[i]) {
root = stack.pop();
}
// 将当前元素入栈
stack.push(postorder[i]);
}
// 返回true
return true;
}