1.701二叉搜索树中的插入操作
有两种插入的操作,在这个题目中,我使用的是将新插入的值放到最下面的叶子节点,而不是改变现有结构来进行一个插入,这样对应的更加方便。
由于搜索二叉树的性质,我们可以直接用一种很简单的方法找到对应的一个结点的位置。
思路:即判断当前值与val的大小来判断是往左移动还是往右移动,移动了之后,直到找到了当前节点的值小于val的时候,且对应的右节点为空,那么添加到右节点位置。如果当前节点的值大于val的时候且当前节点的左节点为空,那么添加一个左节点。
TreeNode* insertIntoBST(TreeNode* root, int val) {
//按照二叉搜索树的性质,查找对应的一个解决,迭代即可
if(root == nullptr){
TreeNode* node =new TreeNode(val);
return node;
}
TreeNode* cur = root;
while(cur){
if(cur->val<val){
if(cur->right == nullptr){
TreeNode* node = new TreeNode(val);
cur->right = node;
return root;
}else{
cur = cur->right;
}
}
if(cur->val>val){
if(cur->left == nullptr){
TreeNode* node = new TreeNode(val);
cur->left = node;
return root;
}else{
cur = cur->left;
}
}
}
return root;
}
2.450删除二叉树中的节点
删除的结点分为五种:
1.没找到需要删除的节点
2.找到了,左右孩子都为空
3.找到了,左孩子为空,右孩子非空
4.找到了,右孩子为空,左孩子非空
5.找到了,左右孩子都为非空
采取递归的方式进行处理二叉树
1.参数的返回值和输入参数:返回是一个节点,输入参数是当前节点和需要比较的值。
2.参数的终止条件:当前节点为空的时候,返回空。
3.这一层的逻辑:第一种的时候返回空,第二种返回空,第三种返回的是右孩子,第四种返回的是返回左孩子。第五种是将左孩子放到右孩子的最左的叶子节点。如果没找到的话,那么就递归返回root。
//思路:如果找到了一个节点的值相等,那么我们就找到这个节点对应的左节点的最右的子节点作为替代或者说是右节点最左的子节点作为替换
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == nullptr) return root; // 第一种情况:没找到删除的节点,遍历到空节点直接返回了
if (root->val == key) {
// 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
if (root->left == nullptr && root->right == nullptr) {
///! 内存释放
delete root;
return nullptr;
}
// 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点
else if (root->left == nullptr) {
auto retNode = root->right;
///! 内存释放
delete root;
return retNode;
}
// 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
else if (root->right == nullptr) {
auto retNode = root->left;
///! 内存释放
delete root;
return retNode;
}
// 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
// 并返回删除节点右孩子为新的根节点。
else {
TreeNode* cur = root->right; // 找右子树最左面的节点
while(cur->left != nullptr) {
cur = cur->left;
}
cur->left = root->left; // 把要删除的节点(root)左子树放在cur的左孩子的位置
TreeNode* tmp = root; // 把root节点保存一下,下面来删除
root = root->right; // 返回旧root的右孩子作为新root
delete tmp; // 释放节点内存(这里不写也可以,但C++最好手动释放一下吧)
return root;
}
}
if (root->val > key) root->left = deleteNode(root->left, key);
if (root->val < key) root->right = deleteNode(root->right, key);
return root;
}
3.669修剪二叉树
修剪二叉树的时候,我们需要比较的就是当前节点与low和high进行比较。1.当前节点值小于low,那么左边的一定是都小的,我们只需要更新右孩子的操作即可。2.如果当前节点值大于high,那么右边的一定是大于这个范围的,我们只需要更新左孩子操作即可。
采用递归的方式来进行操作。
1.函数的返回值和输入:直接就是系统给定的输入和返回值
2.终止条件:当前节点为空,那么直接返回即可。
3.这一层的逻辑:首先判断当前值与low或者high的大小,确定是否在范围内,然后返回节点位置。具体返回的逻辑参考上面。
//使用递归的方法来计算
TreeNode* trimBST(TreeNode* root,int low ,int high){
if(root == nullptr) return root;
if(root->val<low){
TreeNode* right = trimBST(root->right,low,high);
return right;
}
if(root->val>high){
TreeNode* left = trimBST(root->left,low,high);
return left;
}
root->left = trimBST(root->left,low,high);
root->right = trimBST(root->right,low,high);
return root;
}
/*
TreeNode* trimBST(TreeNode* root, int low, int high) {
if(root == nullptr) return root;//第一种情况,该节点为空
if(root->val<low){//第二种情况,如果当前值小于low,那么代表的是左边的一定全都小于low,全部得删除
//此时进行一个深度遍历,将其全部删除
TreeNode* cur = root->left;
stack<TreeNode*> st;
if(cur)st.push(cur);
while(!st.empty()){
TreeNode* node = st.top();
st.pop();
if(node->left)st.push(node->left);
if(node->right)st.push(node->right);
delete node;
}
//删除当前节点
TreeNode* tmp = root;
root = root->right;
delete tmp;
return root;
}
if(root->val>high){//第二种情况,如果当前值小于low,那么代表的是左边的一定全都小于low,全部得删除
//此时进行一个深度遍历,将其全部删除
TreeNode* cur = root->right;
stack<TreeNode*> st;
if(cur)st.push(cur);
while(!st.empty()){
TreeNode* node = st.top();
st.pop();
if(node->left)st.push(node->left);
if(node->right)st.push(node->right);
delete node;
}
//删除当前节点
TreeNode* tmp = root;
root = root->left;
delete tmp;
return root;
}
root->left = trimBST(root->left,low,high);
root->right = trimBST(root->right,low,high);
return root;
}*/
4.108将有序数组变为搜索二叉树
思路:二分法和递归来做一个求解。因为搜索二叉树的一个递增,根据搜索二叉树的性质,我们要将有序数组进行变换的时候,将其转化为一个完全的搜索二叉树,保证左右子树的长度基本相等,从而完成一个相应的操作。
TreeNode* sortedArrayToBST(vector<int>& nums,int left,int right){
if(left>right)return nullptr;//递归中止条件
int mid = left+(right-left)/2;
TreeNode* root = new TreeNode(nums[mid]);
root->left = sortedArrayToBST(nums,left,mid-1);
root->right = sortedArrayToBST(nums,mid+1,right);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
int n = nums.size();
if(n == 0) return nullptr;
return sortedArrayToBST(nums,0,n-1);
}
4.538把二叉搜索树变为累加树
根据题目给定的需求,结合搜索二叉树的性质,我们只需要将中序遍历变为一个反中序遍历即可,即右中左的操作。此时需要操作的就是一个对于中间的操作,用一个全局变量记载累加值,更新当前节点和完成全局变量的更新即可。
int pre = 0;
void traversal(TreeNode* cur) {
if(cur == nullptr)return;
traversal(cur->right);
cur->val += pre;
pre = cur->val;
traversal(cur->left);
}
TreeNode* convertBST(TreeNode* root) {
pre = 0;
traversal(root);
return root;
}
5.阶段性总结
1.二叉树,搜索二叉树,平衡二叉树不同的性质。可以根据对应的性质来降低操作的复杂度。
2.深度遍历和层次遍历的统一方式。
3.构造二叉树。
4.删除节点。
5.查找公共祖先的问题:如何向上递归:回溯算法。