c++ 二叉排序树

二叉排序树

  • 在使用链表的时候,我们碰到的问题都是一对一的线性结构,然而当碰到一对多的时候,链表就无法使用。此时我们需要一对多的数据结构——树。树是非线性的数据结构。

现实生活的树长这样
在这里插入图片描述

而今天要介绍的二叉树和树确实长得很像。
在这里插入图片描述

关于二叉树的性质

  • 每个节点最多可以有两个子节点,并且子树都有左右之分,次序不能颠倒。
  • 二叉树的第i层最多有2的i次方-1个节点,第一层为图中最上层A,往下依次增加。
  • 深度为n的二叉树,最多有2的n次方-1个节点,深度就是从上往下的层数,图中A为一层,BC为一层,DEFG为一层,所以为三层。

二叉查找树

是二叉树的一种,称为查找树,是因为有着以下的特殊性质。

1. 若任意结点的左子树不为空,那么所有左子树的结点的值要小于其父节点的值
2. 若任意结点的右子树不为空,那么所有右子树的结点的值要大于其父节点的值
3. 没有任意两个节点的值一样

在这里插入图片描述
在每次插入时都要进行对比,所以形成了在根节点的左边都是比根节点小的数据,在右边则是比根节点大的数据。并且不会出现重复数据。

.h文件

#include <iostream>
#include <string>
#include <windows.h>
using namespace std;

const int MAX_SIZE = 32767;
const int MIN_SIZE = 0;

class Node
{
public:
    int data;
    Node* left;
    Node* right;
    Node() :data(0), left(NULL), right(NULL) {}
};

class Binary
{
public:
    Binary() :root(NULL), size(0) {}
    ~Binary() {}
    int getSize()const;//获取树的大小
    void insertNode(int data);
    void preTravel();//先序遍历
    void midTravel();//中序遍历
    void postTravel();//后序遍历
    Node* searchKey(int value);//通过value查找某个结点
    void removeTree();//删除整棵树
    void removeNode(int vlaue);
private:
    Node* insert(Node* root, int data);
    void pretraveltree(Node* root);
    void midtraveltree(Node* root);
    void posttraveltree(Node* root);
    Node* searchtree(Node* root, int value);
    void removealltree(Node* root);
private:
    Node* root;//树的根节点
    int size;//树的大小
};

1.创建二叉树及插入数据

void Binary::insertNode(int data)
{
    if (MAX_SIZE <= getSize())
    {
        cerr << "二叉树的结点个数已经到达最大值,无法插入!";
        return;
    }
    root = insert(root, data);
}

Node* Binary::insert(Node* proot, int data)
{
    if (proot == NULL)//当前树为空的情况
    {
        Node* nNode = new Node();
        nNode->data = data;
        proot = nNode;
        size++;
        return proot;
    }

    if (proot->data > data)//如果当前值小于结点值,往左边插入
    {
        proot->left = insert(proot->left, data);
    }
    else if (proot->data < data)//如果当前值大于结点值,往右边插入
    {
        proot->right = insert(proot->right, data);
    }
    else if (proot->data == data)//等于则不插入值
    {
        return proot;
    }
    size++;
    return proot;

}

在这里插入图片描述

2.二叉树的遍历

1. 先序遍历:中->左->右的顺序遍历,如上图按照顺序来为6425879,第一个永远为根节点
2. 中序遍历:左->中->右的顺序遍历,如上图按照顺序来为2456789,在根节点左边的在树中结点也在左边,在根节点右边的在树中也在右边
3. 后序遍历:左->右->中的顺序遍历,如上图按照顺序来为2547986,最后一个遍历的永远是根节点

3.删除某一个结点

在这里插入图片描述

1. 如图,如果删除结点为叶子结点,例如1、4、6、8,直接删除即可。
2. 当删除的结点不为叶子结点,有一个左子树或者右子树时,就要子承父业。例如删除2这个结点时,那么久变成了下图图2。

图2**图2**在这里插入图片描述

3.当删除的结点的左右子节点都存在时,使用其中序遍历相邻结点作为删除结点的替代,然后将用来替代的结点删除。如下图所示中序遍历的顺序为2、4、6、8、10、12、14、16、18、20、22。

在这里插入图片描述

**假设我们要删除8这个结点,那么在按照中序遍历,我们可以用6或者10来替代它。如下图
在这里插入图片描述
附测试cpp代码,.h文件在上面


```cpp
#include "Tree.h"



int Binary::getSize()const
{
    return size;
}

void Binary::insertNode(int data)
{
    if (MAX_SIZE <= getSize())
    {
        cerr << "二叉树的结点个数已经到达最大值,无法插入!";
        return;
    }
    root = insert(root, data);
}

Node* Binary::insert(Node* proot, int data)
{
    if (proot == NULL)//当前树为空的情况
    {
        Node* nNode = new Node();
        nNode->data = data;
        proot = nNode;
        size++;
        return proot;
    }

    if (proot->data > data)//如果当前值小于结点值,往左边插入
    {
        proot->left = insert(proot->left, data);
    }
    else if (proot->data < data)
    {
        proot->right = insert(proot->right, data);
    }
    else if (proot->data == data)
    {
        return proot;
    }
    size++;
    return proot;

}

void Binary::preTravel()
{
    pretraveltree(root);
}

void Binary::pretraveltree(Node* proot)
{
    if (NULL != proot)
    {
        cout << proot->data << "  ";
        pretraveltree(proot->left);
        pretraveltree(proot->right);
    }
}

void Binary::midTravel()
{
    midtraveltree(root);
}

void Binary::midtraveltree(Node* proot)
{
    if (NULL != proot)
    {
        midtraveltree(proot->left);
        cout << proot->data << "  ";
        midtraveltree(proot->right);
    }
}

void Binary::postTravel()
{
    posttraveltree(root);
}

void Binary::posttraveltree(Node* proot)
{
    if (NULL != proot)
    {
        posttraveltree(proot->left);
        posttraveltree(proot->right);
        cout << proot->data << "  ";
    }
}

Node* Binary::searchKey(int value)
{
    if (NULL == root)
    {
        cerr << "树是空的" << endl;
        return NULL;
    }
    return searchtree(root, value);
}

Node* Binary::searchtree(Node* proot,int value)
{
    if (proot->data == value)
    {
        return proot;
    }
    else if (proot->data > value)
    {
        return searchtree(proot->left, value);
    }
    else if (proot->data < value)
    {
        return searchtree(proot->right, value);
    }
}

void Binary::removeTree()
{
    if (NULL == root)
    {
        cerr << "树已经是空的了" << endl;
    }
    removealltree(root);
}

void Binary::removealltree(Node* proot)
{
    if (NULL != proot)
    {
        removealltree(proot->left);
        removealltree(proot->right);
        delete proot;
        proot = NULL;
    }
    size = 0;
}

void Binary::removeNode(int value)
{
    if (NULL == root)
    {
        cerr << "树是空的" << endl;
        return;
    }
    Node* pNode = NULL;
    Node* pDel = root;
    
    while (pDel)//该循环用于找到需要删除的结点和其父节点
    {
        if (value == pDel->data)
        {
            break;
        }
        else if (value > pDel->data)
        {
            pNode = pDel;//用于记录父节点
            pDel = pDel->right;
        }
        else if (value < pDel->data)
        {
            pNode = pDel;
            pDel = pDel->left;
        }
    }



    if (NULL == pDel)
    {
        cerr << "该value不存在于树中" << endl;
        return;
    }


    if ((pDel->left == NULL) && (pDel->right == NULL))//1.左子树和右子树都为空的情况,为叶节点
    {
        if (pDel == root)//整棵树只有一个节点的情况下 
        {
            root = NULL;
            delete pDel;
            pDel = NULL;

            size--;
            return;
        }

        if (pNode->left = pDel)
        {
            pNode->left = NULL;  
        }
        else if (pNode->right = pDel)//父节点的右边为需要删除的结点
        {
            pNode->right = NULL;
        }
        delete pDel;
        pDel = NULL;
        
        size--;
    }
    else if ((pDel->right == NULL) && (pDel->left != NULL))//2.只有左子树的情况
    {
        if (pDel == root)//删除结点为root结点时
        {
            root = pDel->left;
        }
        else
        {
            if (pNode->left == pDel)//父结点的左节点为需要删除的结点时,将父节点跳过原来的需要删除的子节点,直接指向子节点的左子树
            {
                pNode->left = pDel->left;
            }
            else if (pNode->right = pDel)
            {
                pNode->right = pDel->left;
            }
        }
        size--;
    }
    else if ((pDel->right != NULL) && (pDel->left == NULL))//3.只存在右子树的情况
    {
        if (pDel == root)
        {
            root = pDel->right;
        }
        else
        {
            if (pNode->left = pDel)
            {
                pNode->left = pDel->right;
            }
            else if (pNode->right = pDel)
            {
                pNode->right = pDel->right;
            }
        }
        size--;
    }
    else if ((pDel->right != NULL) && (pDel->left != NULL))
    {
        Node* pSuc = pDel->right;
        pNode = pDel;

        while (pSuc->left)
        {
            pNode = pSuc;
            pSuc = pSuc->left;
        }

        pDel->data = pSuc->data;
        if (pSuc == pNode->left)
        {
            pNode->left = pSuc->right;
        }
        else if (pSuc == pNode->right)
        {
            pNode->right = pSuc->right;
        }
        
        pDel = pSuc;
        delete pDel;
        pDel = NULL;
        size--;
    }
}
int main()
{
    Binary tree;


    tree.insertNode(16);
    tree.insertNode(20);
    tree.insertNode(18);
    tree.insertNode(22);
    tree.insertNode(12);
    tree.insertNode(14);
    tree.insertNode(8);
    tree.insertNode(10);
    tree.insertNode(4);
    tree.insertNode(2);
    tree.insertNode(6);

    
    tree.removeNode(12);

    //tree.preTravel();
    tree.midTravel();
    //tree.postTravel();
    return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值