根结点值小于L 根结点和左子树中节点关键码值均小于L 在区间之外 应该全部丢弃 右子树中可能有节点值在区间外 也可能有节点值在区间内 所以对右子树递归裁剪 由于左子树和根结点均被丢弃 所以直接返回右子树裁剪结果的根结点
根结点大于R情形类似
如果根结点在区间内 则不应丢弃 但此时左右子树均可能有节点在区间外,所以对左右子树递归裁剪 裁剪结果链接回根结点
如果二叉搜索树为空 裁剪结果仍为空树 直接返回空指针
更新:2019.6.19
刚才看了一下,递归代码存在一个问题,假若向下搜索过程中找到了一棵根节点无需修剪,但根节点子树可能需要修剪的BST,那么递归函数会在左右子树中递归搜索根节点无需修剪的子树,在搜索过程中遇到的根节点和左子树或右子树需要全部修剪的子树对应递归调用的一层,调用栈中会为该层的函数调用信息开辟栈空间,而这是没有必要的,因为遇到的子树根节点和根节点的左子树(右子树)应全部抛弃,只需修剪根节点的右子树(左子树),因此在这一层为根节点和根节点的左子树(右子树)应该被抛弃的子树保留栈空间是没有必要,造成了空间的浪费,实际上我们只需将搜索过程中遇到的根节点不应被修剪的BST子树的根节点压栈即可,而且整个过程完全可以用非递归的方式实现
自己编写的经过优化后的非递归代码如下
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
struct BSTNode //二叉搜索树节点定义
{
int data; //数据域
BSTNode* left_child = nullptr;
BSTNode* right_child = nullptr;
BSTNode(int d) :data(d) {}
BSTNode(const BSTNode& be_copy) :data(be_copy.data), left_child(nullptr), right_child(nullptr) {}
};
BSTNode *trimBST(BSTNode* root, int left, int right) //修剪二叉搜索树,只保留区间[left, right]内的节点
{
enum ProcessRate {START, LEFT_SUB_TREE, RIGHT_SUB_TREE}; //处理状态,尚未修剪任何子树,已修剪过左子树,两棵子树均已修剪
struct StackNode
{
BSTNode* ptr_to_node_every_layer; //需修剪的BST根节点指针
ProcessRate rate = ProcessRate::START; //修剪状态
BSTNode* ptr_to_root_beconstructed; //修剪后形成的新的BST根节点指针
StackNode(BSTNode* p) :ptr_to_node_every_layer(p)
{
ptr_to_root_beconstructed = new BSTNode(*ptr_to_node_every_layer);
}
};
stack<StackNode> work_stack;
BSTNode* cur = root;
while (cur != nullptr)
{
if (right < cur->data)
{
cur = cur->left_child;
}
else if (cur->data < left)
{
cur = cur->right_child;
}
else
{
work_stack.push(StackNode(cur));
break;
}
}
if (cur == nullptr)
{
return nullptr;
}
while (true)
{
if (work_stack.top().rate != ProcessRate::RIGHT_SUB_TREE)
{
if (work_stack.top().rate == ProcessRate::START) //左子树尚未修剪,修剪左子树
{
cur = work_stack.top().ptr_to_node_every_layer->left_child;
}
else if (work_stack.top().rate == ProcessRate::LEFT_SUB_TREE) //右子树尚未修剪,修剪右子树
{
cur = work_stack.top().ptr_to_node_every_layer->right_child;
}
while (cur != nullptr) //向下搜索,抛弃修剪掉的部分
{
if (right < cur->data)
{
cur = cur->left_child;
}
else if (cur->data < left)
{
cur = cur->right_child;
}
else
{
work_stack.push(StackNode(cur)); //找到根节点无需修剪,但子树需修剪的BST子树
break;
}
}
if (cur == nullptr) //被修剪的子树为空或子树中所有节点值都在[L,R]外
{
if (work_stack.top().rate == ProcessRate::START)
{
work_stack.top().rate = ProcessRate::LEFT_SUB_TREE;
}
else
{
work_stack.top().rate = ProcessRate::RIGHT_SUB_TREE;
}
}
}
else //当前BST左右子树均修剪完毕
{
StackNode temp = work_stack.top();
work_stack.pop();
if (work_stack.empty() == false) //栈不为空,将已经修剪完毕的当前BST链接至上一层需修剪的BST的子女指针域,并更新上一层修剪状态
{
if (work_stack.top().rate == ProcessRate::START)
{
work_stack.top().ptr_to_root_beconstructed->left_child = temp.ptr_to_root_beconstructed;
work_stack.top().rate = ProcessRate::LEFT_SUB_TREE;
}
else if (work_stack.top().rate == ProcessRate::LEFT_SUB_TREE)
{
work_stack.top().ptr_to_root_beconstructed->right_child = temp.ptr_to_root_beconstructed;
work_stack.top().rate = ProcessRate::RIGHT_SUB_TREE;
}
}
else
{
return temp.ptr_to_root_beconstructed; //如果栈为空,说明当前已经修剪完毕的BST子树就是最终修剪结果,直接返回
}
}
}
}
void inorderTraverse(BSTNode* root) //输出中序序列
{
if (root != nullptr)
{
inorderTraverse(root->left_child);
cout << root->data << " ";
inorderTraverse(root->right_child);
}
}
int main()
{
BSTNode* root = nullptr;
vector<int> input{4, 89, 23, 46, 12, 3, 56, 78, 34, 45, 11}; //插入BST中的数据
for (const int& i : input)
{
BSTNode* temp = root;
if (temp == nullptr)
{
root = new BSTNode(i);
}
else
{
BSTNode* parent = nullptr;
while (temp != nullptr)
{
if (temp->data == i)
break;
parent = temp;
if (temp->data < i)
{
temp = temp->right_child;
}
else if (temp->data > i)
{
temp = temp->left_child;
}
}
if (temp == nullptr)
{
if (i < parent->data)
{
parent->left_child = new BSTNode(i);
}
else
{
parent->right_child = new BSTNode(i);
}
}
}
}
BSTNode* _new = trimBST(root, 5, 50);
cout << "修剪后的二叉树的中序序列为:";
if (_new == nullptr)
{
cout << "NULL";
}
else
{
inorderTraverse(_new);
}
cout << endl;
return 0;
}
仅供参考