构造有序二叉树.cpp

/*构造有序二叉树,插入元素并遍历打印
 * 要求左子树大于根节点大于右子树
 *二叉树特点:有且仅有一个根节点
 *每个根节点只有一个直接前驱和最多两个直接后继
 */
#include <iostream>
using namespace std;

class Tree {
//树的辅助结构体,一个节点包括数据和指向左右子树的两个指针
    struct Node {
        int data;
        Node* left;
        Node* right;
    };
public:
//无参构造函数(构造一棵空树)
    Tree() : root(NULL) { }
//插入节点
    Tree& Add(const int& data)
    {
        add(root, data);
        return *this;
    }
//查找节点
    bool Search(const int& data)
    {
        Node* p = root;
        while (p != NULL) {
            if (data < p->data) {
                p = p->left;
            } else if (data > p->data) {
                p = p->right;
            } else {
                return true;
            }
        }
        return false;
    }
//删除节点
    Tree& Remove(const int& data)
    {
        Node* p = root;
        Node* parent = NULL;
        //1.找到该节点,并保存其父节点
        while (p != NULL) {
            if (data < p->data) {//数据比根节点小,则在根节点左侧
                parent = p;//父节点指向p
                p = p->left;//p指向p的左子树
            } else if (data > p->data) { //数据比根节点大,同理
                parent = p;
                p = p->right;
            } else { //数据和根节点相等
                break;
            }
        }
        //2.将其父节点和子节点重新链接
         //2.1 空二叉树
        if (p == NULL) {//空二叉树,无需处理
            return *this;
        }
         //2.2左右子树为空
        if (p->left==NULL && p->right==NULL) {
            if (p == root) { //如果p是根节点
                root = NULL;//将根节点置空
            } else if (data < parent->data) { //如果p是左子树
                parent->left = NULL;//将左子树置空
            } else { //p是右子树
                parent->right= NULL;//将右子树置空
            }
        }
        //2.3 左子树不为空,右子树为空
        else if (p->left!=NULL && p->right==NULL) {
            if (p == root) {
                root = p->left;
            } if (data < parent->data) {
                parent->left = p->left;
            } else {
                parent->right= p->left;
            }
        }
         //2.4左子树为空,右子树不为空
        else if (p->left==NULL && p->right!=NULL) {
            if (p == root) {
                root = p->right;
            } if (data < parent->data) {
                parent->left = p->right;
            } else {
                parent->right= p->right;
            }
        }
         //2.5左右子树都不为空
        else if (p->left!=NULL && p->right!=NULL) {
            if (p == root) { //如果要删除的是根节点,
                root = p->right;
            } else if (data < parent->data) {//如果要删除的是左子树
                parent->left = p->right;
            } else {
                parent->right= p->right;
            }
            
            Node* t = p->right;//因为删除任意一个节点,其位置都会由其右子树继承,保存p的右子树,将p的左子树链接到右子树的尾节点
            while (t->left != NULL) {
                t = t->left;
            }
            t->left = p->left;
        }
                   
        delete p; //删除p并释放p的内存
        return *this;
    }
//打印二叉树
    Tree& Print()
    {
        print(root);
        printf("\n");
        return *this;
    }
private:
//打印二叉树,外部不可访问
    void print(Node* p)
    {
        if (p != NULL) {
            print(p->left);         
            printf("%d ", p->data);
            print(p->right);         
        }
    }
//添加节点,外部不可访问,保证二叉树安全,递归添加
    void add(Node*& p, const int& data)
    {
        if (p == NULL) { //p为空,添加的节点即根节点,其左右子树为空
            p = new Node;
            p->data = data;
            p->left = NULL;
            p->right= NULL;
        } else if (data < p->data) //如果数据比父节点小,作为父节点的左子树
        {
            add(p->left, data);
        } else if (data > p->data) //如果数据比父节点大,作为父节点的右子树
        {
            add(p->right,data);
        }
    }


    Node* root;
};

int main()
{
    Tree t;
    t.Add(30);
    t.Add(20).Add(10).Add(25).Add(21);
    t.Add(40).Add(80).Add(70).Add(90);
    cout << "打印二叉树 : "<<endl;
    t.Print();
    cout << "40是否在二叉树中 : "<<endl;
    cout << t.Search(40) << endl;
    cout << "删除30 : "<<endl;
    t.Remove(30).Print();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值