二叉搜索树模拟实现及性能分析

本文详细介绍了二叉搜索树的模拟实现过程,包括插入、删除、查找等核心操作,并通过代码示例展示了如何构建和使用二叉搜索树。同时,分析了二叉搜索树的性能特点,指出其平均查找长度取决于结点深度,最优和最差情况下的性能分别为O(logN)和O(N/2)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上一篇文章中我们已经将二叉搜索树的基本性质看了,本片文章将介绍二叉树的模拟实现与性能分析,下面给出二叉树的模拟实现:

#include <iostream>
using namespace std;

// 定义二叉搜索树结点
template<class T>
struct BSTNode {
    BSTNode(const T& data = T())
        : _pleft(nullptr)
        , _pright(nullptr)
        , _data(data)
    {}
    BSTNode<T>* _pleft;
    BSTNode<T>* _pright;
    T _data;
};

// 定义二叉搜索树
template<class T>
class BSTree {
    typedef BSTNode<T> Node;
    typedef Node* pNode;
public:
    BSTree()
        : _proot(nullptr)
    {}

    pNode Copy(pNode root) {
        if(root == nullptr) {
            return nullptr;
        }
        
        // 将root的值、左子树、右子树分别拷贝到临时
        // 的newroot中
        pNode newroot = new Node(root->_data);
        newroot->_pleft = Copy(root->_pleft);
        newroot->_pright = Copy(root->_pright);
        return newroot;
    }
    BSTree(const BSTree<T>& tree) {
        _proot = Copy(tree._proot);
    }


    ~BSTree() {
        destory(_proot);
    }

    // 赋值运算符重载
    BSTree<T>& operator=(const BSTree<T>& tree) {
        if(this != tree) {
            destory(this->_proot);
            this->_proot = Copy(tree._proot);
        }
        return *this;
    }

    BSTree<T>& operator=(BSTree<T> tree) {
        swap(this->_proot, tree._proot);
        return *this;
    }
    
    
    // 查询
    pNode Find(const T& data) {
        pNode cur = _proot;
        while(cur) {
            if(data == cur->_data) {
                return cur;

            } else if (data > cur->_data) {
                // 如果要查找的值比当前节点的值大,则去右子树查找
                cur = cur->_pright;                              
            } else {
                // 否则就去左子树查找
                cur = cur->_pleft;
            }
            return nullptr;
        }   
    }

    // 插入
    bool Insert(const T& data)  {
        // 如果为空则直接插入
        if(_proot == nullptr) {
            _proot = new Node(data);
            return true;
        }

        // 树不为空则需要按照二叉搜索树的性质
        // 查找data在树中的插入位置
        pNode cur = _proot;

        // 记录pcur的父结点
        pNode parent = nullptr;
        while(cur) {
            parent = cur;
            if(data < cur->_data) {
                cur = cur->_pleft;
            } else if(data > cur->_data) {
                cur = cur->_pright;
            } else {
                return false;
            }
        }

        // 找到插入位置后开始插入元素
        cur = new Node(data);
        if(data < parent->_data) {
            parent->_pleft = cur;
        } else {
            parent->_pright = cur;
        }
        return false;
    }

    // 删除结点
    bool Erase(const T& data) {
        
        // 如果树为空,则删除失败
        if(_proot == nullptr) {
            return false;
        }

        // 查找data在树中的位置
        pNode cur = _proot;
        pNode parent = nullptr;
        while(cur) {
            if(data > cur->_data) {
                parent = cur;
                cur = cur->_pright;
            } else if (data < cur->_data){
                parent = cur;
                cur = cur->_pleft;
            } else {
                pNode del = cur;
                // 如果当前节点的左子树为空
                if(cur->_pleft == nullptr) {
                    // 并且当前节点的父节点也为空
                    if(parent == nullptr) {
                        // 判断右子树是否为空
                        _proot = _proot->_pright;
                    } else {
                        // 如果当前节点的左子树不为空
                        // 则继续判断其父节点的左子树是否为当前节点
                        if(parent ->_pleft == cur) {
                            // 如果是,在判断父节点的左子树是否等于当前节点右子树
                            parent->_pleft = cur->_pright;
                        } else {
                            // 如果不是,则判断父节点右子树是否等于当前节点右子树
                            parent->_pright = cur->_pright;
                        }
                    }
                } else if(cur->_pright == nullptr) {
                    // 如果当前节点右子树为空,判断其父节点是否为空
                    if(parent == nullptr) {
                        // 为空,则直接删除
                        _proot = _proot->_pleft;
                    } else {
                        if(cur == parent->_pleft) {
                            parent->_pleft = cur->_pleft;
                        } else {
                            parent->_pright = cur->_pleft;
                        }
                    }
                } else {
                    // 找替代节点
                    pNode replace = cur->_pright;
                    pNode p_replace = cur;
                    while(replace->_pleft) {
                        p_replace = replace;
                        replace = replace->_pleft;
                    }

                    cur->_data = replace->_data;
                    if(p_replace->_pleft == replace) {
                        p_replace->_pleft = replace->_pright;
                    } else {
                        p_replace->_pright = replace->_pright;
                    }
                    del = replace;
                }
                delete del;
                return true;

            }
        }
        return false;
    }


    // 中序遍历 :左——>根——>右
    void Inorder() {
        _Inorder(_proot);
        cout << endl;
    }
    void _Inorder(pNode root) {
        if(root) {
            _Inorder(root->_pleft);
            cout << root->_data << " ";
            _Inorder(root->_pright);
        }
    }

    // 销毁
    void destory(pNode& root) {
        if(root == nullptr) {
            return;
        }

        destory(root->_pleft);
        destory(root->_pright);
        delete _proot;
    }
private:
    pNode _proot;

};
int main()
{
    BSTree<int> B;
    B.Insert(9);
    B.Insert(2);
    B.Insert(4);
    B.Insert(6);
    B.Insert(1);
    B.Insert(2);
    B.Insert(8);
    B.Insert(7);
    B.Insert(5);
    B.Insert(0);
    BSTree<int> B1(B);
    B.Inorder();

    int arr[] = {1,0,2,4,3,6,7,9,5,8};
    for(auto e : arr) {
        B.Erase(e);
    }
    B.Inorder();
    B1.Inorder();

    return 0;
}

经过测试,我们可以对二叉搜索树的性能进行分析如下:

①插入和删除之前都必须先进行查找插入删除位置,所以说查找的效率代表了二叉搜索树的整体效率

②对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。

③最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:O(logN)

最差情况下,二叉搜索树退化为单支树,其平均比较次数为:O(N/2)

由于二叉搜索树的平衡性极度不平衡所以这里又引出了AVL树,欲知AVl树详情,请看我的下篇博客.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值