二叉搜索树

https://mp.weixin.qq.com/s?__biz=MzU0ODMyNDk0Mw==&mid=2247495540&idx=1&sn=214e962041b5c8e9a70bd4059371ad05&chksm=fb427c54cc35f542e1b3ef7c9fd6ed5b6267843e12e0d93d282c2bd2fdac59edc6bec83fd9a1&scene=27

1 普通二叉搜索树

template <typename T>
struct BSTNode
{
    struct BSTNode<T> *left;
    struct BSTNode<T> *right;
    T _key;
    
    BSTNode(const T& key): _key(key), left(nullptr), right(nullptr)
    {
    }
};

1.1 查找

步骤如下:

  1. 如果当前节点为空,则搜索失败。
  2. 否则,如果当前节点的值等于要查找的值,则直接返回。
  3. 否则,如果要查找的值比当前节点小,就往当前节点的左子树找。如果要查找的值比当前节点值大,就往当前节点的右子树找。
    在这里插入图片描述

1.1.1 迭代查找

template <typename T>
BSTNode<T>* find(BSTNode<T>* root, const T& key)
{
    BSTNode<T>* ret = root;
    while(ret && key != ret->_key) {
        if(key < ret->_key){
            ret = ret->left;
        }
        else{
            ret = ret->right;
        }
    }
    return ret;
}

1.1.2 递归查找

template<typename T>
BSTNode<T>* iterfind(BSTNode<T>* root, const T& key)
{
    if(nullptr == root) {
        return nullptr;
    }

    if(key == root->_key) {
        return root;
    }
    if(key > root->_key) {
        return iterfind(root->right, key);
    }
    else {
        return iterfind(root->left);
    }
}

1.2 插入

1.2.1 迭代混入

总体思路‌:

  • 从根节点开始,根据待插入节点的值与当前节点的值比较,决定向左子树还是右子树移动。
  • 使用一个指针遍历二叉树,直到找到空位置插入新节点。
template<typename T>
bool insert(BSTNode<T>* root, const T& key)
{
    if(nullptr == root) {
        return false;
    }

    BSTNode<T>* ptr = root;
    while(ptr) {
        if(key > ptr->_key) {
            if(nullptr == ptr->right){
                ptr->right = new BSTNode<T>(key); 
                return true;
            }
            else{
                ptr = ptr->right;
            }
        }
        else if(key < ptr->_key){
            if(nullptr == ptr->left){
                ptr->left = new BSTNode<T>(key);
                return true;
            }
            else{
                ptr = ptr->left;
            }
        }
        else{
            return true;
        }
    }
    return false;
}

1.2.2 递归插入

template <typename T>
bool insert(BSTNode<T>* root, const T& key)
{
    if(nullptr == root) {
        return false;
    }

    if(key == root->_key) {
        return true;
    }
    if(key > root->_key) {
        insert(root->right, key);
    }
    else{
        insert(root->left, key);
    }
}

1.3 删除

删除比较麻烦要考虑三种情况:

  • 要删除的是叶子节点:直接删除,再将父节点指向叶子节点的指针置为NULL.
  • 要删除的节点只有一个子节点:将其父节点指向待删除节点的子节点
  • 要删除的节点有左右节点:用另一个节点替代被删除节点,如左边树的最大元素,或者右边树的最小元素。而且替代节点是一定没有两个子节点的,所以可以将问题简单化

1.3.1 迭代删除

template<typename T>
bool deletenode(BSTNode<T>* root, const T& key)
{
    if(nullptr == root) {
        return false;
    }

    BSTNode* cur = root;
    BSTNode* par = nullptr;

    while(cur)
    {
        if(key == cur->_key) {
            if(nullptr == cur->left && nullptr == cur->right)
            {
                if(cur != root) {
                    if(par->left == cur) {
                        par->left = nullptr;
                    }
                    else {
                        par->right = nullptr;
                    }
                }
                delete cur;
                cur = nullptr;
            }
            else if(nullptr == cur->left)
            {
                if(cur != root) {
                    if(par->left == cur) { // 确认是父亲的左孩子还是右孩子
                        par->left = cur->right;
                    }
                    else {
                        par->right = cur->right;
                    }
                }
                else { // 用新的节点替换root
                    root = root->right;
                }
                delete cur;
                cur = nullptr;
            }
            else if(nullptr == cur->right)
            {
                if(cur != root) {
                    if(par->left == cur) {
                        par->left = cur->left;
                    }
                    else {
                        par->right = cur->left;
                    }
                }
                else {
                    root = root->left;
                }
                delete cur;
                cur = nullptr;
            }
            else//找右孩子最大
            {
                BSTnode* min = cur->right;
                BSTNode* minpar = nullptr;
                while(min->left)
                {
                    minpar = min;
                    min = min->left;
                }

                swap(cur->_key, min->_key);

                if(minpar->left == min) {
                    minpar->left = nullptr;
                }
                else {
                    minpar->right = nullptr;
                }

                delete min;
                min = null;
            }
            return true;
        }
        if(key < cur->_key) {
            par = cur;
            cur = cur->left;
            continue;
        }
        else {
            par = cur;
            cur = cur->right;
            continue;
        }
    }
    return false;
}

1.3.2 递归删除

bool _EraseR(Node*& root, const K& key)
{
	Node* del = root;
	if (root == nullptr)
		return false;
	if (root->_key < key)
		return _EraseR(root->_right, key);
	else if (root->_key > key)
		return _EraseR(root->_left, key);
	else
	{
		if (root->_left == nullptr)
			root = root->_right;
		else if (root->_right == nullptr)
			root = root->_left;
		else
		{
			//找右数的最左节点替换删除
			Node* min = root->_right;
			while (min->_left)
			{
				min = min->_left;
			}
			swap(root->_key, min->_key);
			//交换后结构改变不是搜索二叉树了,规定范围在右树(因为是右树最左节点替换)再递归
			return _EraseR(root->_right, key); 
		}
		delete del;
		return true;	
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值