二叉搜索树的增删查(递归与非递归)实现

来源:互联网 发布:python unpackbits 编辑:程序博客网 时间:2024/05/29 17:37

二叉搜索树(BinarySearchTree):
二叉搜索树性质:
1. 每个节点都有一个作为搜索依据的关键码(key),所有节点的关键码互不相同。
2. 左子树上所有节点的关键码(key)都小于根节点的关键码(key)。
3. 右子树上所有节点的关键码(key)都大于根节点的关键码(key)。
4. 左右子树都是二叉搜索树。

如图:是一个二叉搜索树
第三方

本文将实现二叉搜索树的插入删除查找

我们先定义一个二叉搜索树的结点结构体

template<class K>struct BinarySearchTreeNode{    BinarySearchTreeNode<K>* _left;    BinarySearchTreeNode<K>* _right;    K _key;    BinarySearchTreeNode(const K& key)        :_left(NULL)        , _right(NULL)        , _key(key)    {}};

插入

插入的返回类型为bool,因为有可能会插入失败
搜索二叉树还有一个特点就是不能有重复的数,因为有重复的数会导致冗余

思想(非递归):我们完成插入的函数需要定义两个结点,cur和parent,我们需要用parent来记录cur的父亲,进入函数首先判断这棵树是否为空,若为空,直接新建结点,并且返回值为true,我们将_root给cur,我们首先要遍历一下这棵树,比根小的向左边走,比根大的向右边走,在这里每次走之前都要先将cur的值给parent,如果相等则返回false(二叉搜索树不能有重复的结点,会冗余),
找到key放的位置后,我们要判断key在parent的左边还是右边,如果在左边,则让parent->_left等于存放key值的结点,反之让parent->_right等于存放key的结点。最后返回true,这样我们的非递归插入就实现好了。(注意:在这里的插入不能用我们下面实现的Find()函数,因为Find()函数只能返回当前结点,而当前节点的parent找不到。没有parent我们Insert()就无法判断结点放左边还是右边)

bool Insert(const K& key)    {        if (_root == NULL)        {            _root = new Node(key);            return true;        }        Node* parent = NULL;        Node* cur = _root;        while (cur)        {            if (cur->_key < key)            {                parent = cur;                cur = cur->_right;            }            else if (cur->_key > key)            {                parent = cur;                cur = cur->_left;            }            else            {                return false;            }        }        if (parent->_key > key)        {            Node* tmp = new Node(key);            parent->_left = tmp;        }        else        {            Node* tmp = new Node(key);            parent->_right = tmp;        }        return true;    }

插入(递归实现)思想:
插入的递归实现主要是利用了root的引用,在这里root有两层含义,一个是当前的值,一个是上一层的值也就是当前值的parent。递归实现代码相对简单,但是不太容易理解。

    bool _InsertR(Node* &root, const K& key)    {        if (root == NULL)        {            root = new Node(key);            return true;        }        if (root->_key > key)        {            _InsertR(root->_left,key);        }        else if (root->_key < key)        {            _InsertR(root->_right,key);        }        else        {            return false;        }    }

查找
思想:查找的函数思想就很简单了,只要cur为真就进入循环:比根小的向左边走,比根大的向右边走等于根就返回cur.

Node* Find(const K& key)    {        Node* cur = _root;        while (cur)        {            if (cur->_key < key)            {                cur = cur->_right;            }            else if (cur->_key > key)            {                cur = cur->_right;            }            else            {                return cur;            }        }        return NULL;    }

删除
二叉搜索树的删除是在这里最重要的
删除可以分为三种情况:
1,左为空
2,右为空
3,两边都不为空。

删除的非递归思想:
我们先遍历一下这棵树,找到要删除的结点,我们把当前要删除的结点给del,先看左为空,
先判断当前要删除的结点是不是根,是根的话就把根给根的右孩子。
不是根的话,我们需要判断的是cur在parent的左边还是右边
用一幅图来讲解
的

右为空的情况跟作左为空是相似的,就还是用图直白的解释一下
树的深度

第三种情况:左右都不为空
我们如果直接删除一个左右都不为空的结点,会导致他的左右孩子没有父亲,导致野指针情况发生,我们在这里可以找一个结点去替换一个左右都不为空的结点,然后删除这个结点,那么这个结点应该选择哪个呢:
我们可以找左子树的最右结点(左子树中最大的数)或者右子树的最左结点(右子树中最小的数),本文使用的是右子树的最左结点,暂且把它叫做subleft,去替换要删除的这个数,然后删除subleft。这样我们的二叉树就还是二叉搜索树。
这里需要特别注意的一点是我们不能将parent的初始值给为NULL,而要给成cur.
我们这里parent是subleft的父亲,和上面一样我们要判断subleft在parent的左边还是右边,两边情况不一样。

bool Remove(const K& key)    {        Node* parent = NULL;        Node* cur = _root;        while (cur)        {            if (cur->_key < key)            {                parent = cur;                cur = cur->_right;            }            else if (cur->_key > key)            {                parent = cur;                cur = cur->_left;            }            else            {                //1,左为空 或 右为空                //3,左右都不为空                Node* del = cur;                //左为空                if (cur->_left == NULL)                {                    if (cur == _root)                    {                        _root = cur->_right;                    }                    else                    {                        if (cur == parent->_right)                        {                            parent->_right = cur->_right;                        }                        else                        {                            parent->_left = cur->_right;                        }                    }                }                //右为空                else if (cur->_right == NULL)                {                    if (cur == _root)                    {                        _root = cur->_left;                    }                    else                    {                        if (cur == parent->_right)                        {                            parent->_right = cur->_left;                        }                        else                        {                            parent->_left = cur->_left;                        }                    }                }                //左右都不为空                else                {                    Node* parent = cur;                    Node* subleft = cur->_right;                    while (subleft->_left)                    {                        parent = subleft;                        subleft = subleft->_left;                    }                    cur->_key = subleft->_key;                    del = subleft;                    if (parent->_left == subleft)                    {                        parent->_left = subleft->_right;                    }                    else                    {                        parent->_right = parent->_left;                    }                }                delete del;                return true;            }        }    }

删除(递归实现)
这里特别要注意的是root的引用
这是递归实现的关键

bool _RemoveR(Node* &root, const K& key)    {        if (root == NULL)        {            return false;        }        if (root->_key < key)        {            return _RemoveR(root->_right, key);        }        else if (root->_key > key)        {            return _RemoveR(root->_left, key);        }        else        {            //1,左为空或右为空            //2,左右都不为空            if (root->_left == NULL)            {                root = root->_right;            }            else if (root->_right == NULL)            {                root = root->_left;            }            else            {                Node* del = root;                //找到了                //左为空,右为空,都不为空                if (root->_left == NULL)                {                    root = root->_right;                }                else if (root->_right == NULL)                {                    root = root->_left;                }                else                {                    Node* parent = root;                    Node* subLeft = root->_right;                    while (subLeft->_left)                    {                        parent = subLeft;                        subLeft = subLeft->_left;                    }                    root->_key = subLeft->_key;                    del = subLeft;                    if (parent->_left == subLeft)                    {                        parent->_left = subLeft->_right;                    }                    else                    {                        parent->_right = subLeft->_right;                          }                }                delete del;                return true;            }        }

中序遍历:我们中序遍历出来的结果是有序的。

void Inorder()    {        _Inorder(_root);        cout << endl;    }    void _Inorder(Node* root)    {        if (root == NULL)        {            return;        }        _Inorder(root->_left);        cout << root->_key << " ";        _Inorder(root->_right);    }

我们要让每个key对应一个value
我们就要给代码中加入value
下面完整代码是我们实现的二叉搜索树的key-value树

#include<iostream>#include<assert.h>using namespace std;template<class K,class V>struct BinarySearchTreeNode{    BinarySearchTreeNode<K,V>* _left;    BinarySearchTreeNode<K,V>* _right;    K _key;    V _value;    BinarySearchTreeNode(const K& key,const V& value)        :_left(NULL)        , _right(NULL)        , _key(key)        , _value(value)    {}};template<class K,class V>class BinarySearchTree{    typedef BinarySearchTreeNode<K,V> Node;public:    BinarySearchTree()        :_root(NULL)    {}    bool Insert(const K& key,const V& value)    {        if (_root == NULL)        {            _root = new Node(key,value);            return true;        }        Node* parent = NULL;        Node* cur = _root;        while (cur)        {            if (cur->_key < key)            {                parent = cur;                cur = cur->_right;            }            else if (cur->_key > key)            {                parent = cur;                cur = cur->_left;            }            else            {                return false;            }        }        if (parent->_key > key)        {            Node* tmp = new Node(key,value);            parent->_left = tmp;        }        else        {            Node* tmp = new Node(key,value);            parent->_right = tmp;        }        return true;    }    void InsertR(const K& key,const V& value)    {        _InsertR(_root,key,value);    }    bool _InsertR(Node* &root, const K& key, const V& value)    {        if (root == NULL)        {            root = new Node(key,value);            return true;        }        if (root->_key > key)        {            _InsertR(root->_left,key,value);        }        else if (root->_key < key)        {            _InsertR(root->_right,key,value);        }        else        {            return false;        }    }    Node* Find(const K& key)    {        Node* cur = _root;        while (cur)        {            if (cur->_key < key)            {                cur = cur->_right;            }            else if (cur->_key > key)            {                cur = cur->_right;            }            else            {                return cur;            }        }        return NULL;    }    bool Remove(const K& key)    {        Node* parent = NULL;        Node* cur = _root;        while (cur)        {            if (cur->_key < key)            {                parent = cur;                cur = cur->_right;            }            else if (cur->_key > key)            {                parent = cur;                cur = cur->_left;            }            else            {                //1,左为空 或 右为空                //3,左右都不为空                Node* del = cur;                //左为空                if (cur->_left == NULL)                {                    if (cur == _root)                    {                        _root = cur->_right;                    }                    else                    {                        if (cur == parent->_right)                        {                            parent->_right = cur->_right;                        }                        else                        {                            parent->_left = cur->_right;                        }                    }                }                //右为空                else if (cur->_right == NULL)                {                    if (cur == _root)                    {                        _root = cur->_left;                    }                    else                    {                        if (cur == parent->_right)                        {                            parent->_right = cur->_left;                        }                        else                        {                            parent->_left = cur->_left;                        }                    }                }                //左右都不为空                else                {                    Node* parent = cur;                    Node* subleft = cur->_right;                    while (subleft->_left)                    {                        parent = subleft;                        subleft = subleft->_left;                    }                    cur->_key = subleft->_key;                    del = subleft;                    if (parent->_left == subleft)                    {                        parent->_left = subleft->_right;                    }                    else                    {                        parent->_right = parent->_left;                    }                }                delete del;                return true;            }        }    }    bool RemoveR(const K& key)    {        return _RemoveR(_root,key);        cout << endl;    }    bool _RemoveR(Node* &root, const K& key)    {        if (root == NULL)        {            return false;        }        if (root->_key < key)        {            return _RemoveR(root->_right, key);        }        else if (root->_key > key)        {            return _RemoveR(root->_left, key);        }        else        {            //1,左为空或右为空            //2,左右都不为空            if (root->_left == NULL)            {                root = root->_right;            }            else if (root->_right == NULL)            {                root = root->_left;            }            else            {                Node* del = root;                //找到了                //左为空,右为空,都不为空                if (root->_left == NULL)                {                    root = root->_right;                }                else if (root->_right == NULL)                {                    root = root->_left;                }                else                {                    Node* parent = root;                    Node* subLeft = root->_right;                    while (subLeft->_left)                    {                        parent = subLeft;                        subLeft = subLeft->_left;                    }                    root->_key = subLeft->_key;                    del = subLeft;                    if (parent->_left == subLeft)                    {                        parent->_left = subLeft->_right;                    }                    else                    {                        parent->_right = subLeft->_right;                          }                }                delete del;                return true;            }        }    }    void Inorder()    {        _Inorder(_root);        cout << endl;    }    void _Inorder(Node* root)    {        if (root == NULL)        {            return;        }        _Inorder(root->_left);        cout << root->_key << root->_value<<" ";        _Inorder(root->_right);    }private:    Node* _root;};void Test(){    BinarySearchTree<int,int> b;    /*b.InsertR(0)*/;    int a[] = { 4, 5, 1, 2, 0, 3, 9, 8, 7, 6 };    for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)    {        b.InsertR(a[i],i);    }    b.Inorder();    b.RemoveR(5);    b.RemoveR(1);    b.RemoveR(4);    b.RemoveR(2);    b.RemoveR(0);    b.RemoveR(6);    b.RemoveR(8);    b.Inorder();}
原创粉丝点击