C++之二叉搜索

1.二叉搜索树的概念

二叉搜索树又称为二叉排序树,它有以下的特点。

1.如果它的左子树不为空,则左子树上所以结点的值都小于等于根结点的值

2.如果它的右子树不为空,则右子树上所有结点都大于等于根结点的值

3.它的左右子树也分别为二叉搜索树

4.二叉搜索树中可以支持插入相等的值,也可以不支持插入相等的值,具体看使用场景定义

2.二叉搜索树的性能分析 

最优情况下,二叉树搜索树为完全二叉树,其高度为O(log2 N

最差情况下,二叉搜索树退化为单支树,其高度为O(N/2)

所以综合来看二叉搜索树增删查改的时间复杂度为:O(N)

3.二叉搜索树的插入

插入的具体过程如下:

1.树为空,则直接新增结点,赋值给root指针

2.树不为空,按二叉搜索树的性质,小的往左边插,大的往右边插。

3,如果支持插入相等的值,插入值跟当前结点相等的值可以往右走,也可以往左走,找到空位置,插入新结点。

4.二叉搜索树的查找

1.从根开始比较,查找X,X比根的值大则往右边走查找,X比根值小则往左边走查找。

2.最多查找高度次,走到空,还没找到,这个值不存在。

3.如果不支持插入相等的值,找到X即可返回

4.如果支持插入相等的值,就要返回最下方的X的值,如下图,要返回最下面的3:

5.二叉搜索树的删除 

首先查找元素是否在二叉搜索树中,如果不存在,则返回false。

如果查找元素则可以分为以下四种情况:

1.要删除结点N左右孩子均为空

2.要删除的结点N左孩子位空,右孩子结点不为空

3.要删除的结点N右孩子位空,左孩子结点不为空

4.要删除的结点N左右孩子结点都不为空

对应以上四种情况的解决方案:

解决1:把N结点父亲对应孩子指针指向空,直接删除N结点

解决2:把N结点父亲对应孩子指针指向右孩子结点,直接删除N结点

解决3:   把N结点父亲对应孩子指针指向左孩子结点,直接删除N结点

解决4:这样的情况无法直接删除N结点,因为N的两个孩子无处安放,只能用替换法删除,找N左子树的值最大结点R(最右结点)或者N右子树的值最小结点R(最左结点)替代N,因为这两个结点中任意一个,放到N的位置,都满足二叉搜索树的规则。替代N的意思就是N和R两个结点的值交换。最后可以根据解决1的方法删除N。

6.二叉搜索树的实现代码

template<class K>

struct BSTNode

{

      K_key;

      BSTNode<K>*_left;

      BSTNode<K>*_right;

      BSTNode(const K& key)

                     :_key(key)

                     ,_left(nullptr)

                     ,_right(nullptr)

 {}

};

 //以下为二叉搜索树的视线

template<class K>

class BSTree

{

     typedef BSTNode<K> Node;

public:

     bool insert(const K& key)

     {

            if(_root == nullptr)

            {

                 _root = new Node(key);

                 return true;

            }

            Node* parent = nullptr;

            Node*cur = _root;

            while(cur)

          {

             if(cur->_key>key)

           {
                 parent = cur;

                 cur = cur->left;

          }

           else if(cur->_key<key)

           {

               parent = cur;

               cur = cur->right;

           }

           else 

          {
               return false;

          }
        }

           cur = new Node(key)

       if(parent->_key<key)

        {

              parent->right = cur;

        }

       if(parent->_key>key)

        {

              parent->left = cur;

        }

    return true;

 }

//以下为二叉搜索树的查找功能

   bool  Find(const K&key)

 {

     Node*cur = _root;

     while(cur)

 {
      if(cur->_key <key)

    {

        cur = cur->right;

    }

      else if(cur->_key>key)

    {

        cur = cur->left;

    }     

       else

    {

        return true;

     }

    return false;

 }

//以下为二叉搜索树的删除功能

  bool  Erase(const K& key)

 {
       Node* parent = nullptr;

       Node*cur =  _root;

       while(cur)

    {
       if(cur->_key < key)

       {
           parent = cur;

           cur = cur->right;

       } 

       else if

      {

           parent = cur;

           cur = cur->left;

      }

      else

     {

          if(cur->left = nullptr)

          {

              if(parent == nullptr)

            { 

                 _root = cur->right;

            }

            else

            {

                  if(parent->left == cur)

                  { 

                         parent->left = cur->right;

                  }

                  else

                  {

                        parent->right = cur->right;

                  }

            }

           delete cur;

           return true;

           else if(cur->right = nullptr)

          {

              if(parent == nullptr)

             { 

                 _root = cur->left;

             }

            else

            {

                  if(parent->left == cur)

                  { 

                         parent->left = cur->left;

                  }

                  else

                  {

                        parent->right = cur->left;

                  }

             }

              delete cur;

              return true;

         }

         

        {

            Node*minp  = cur;

            Node*min    = cur->right;

            while(min->left)

          {

             minp = min;

             min  = min->left;

          }

          cur->key = min->key;

          if(minp->left == min)

            minp->left = min->right;

          else

            minp->right = min->right;

          delete min;

           return true;

         }

      }

   }   

     return false;

           

        }

        

           

7.二叉搜索树key和key/value使用场景

    7.1 key搜索场景

只有key作为关键码,结构中只需要存储key即可,关键码即为需要搜索到的值,搜索场景只需要判断key在不在。key的搜索场景实现的二叉树搜索树支持增删查,不支持修改的原因是修改key会破坏二叉树的结构。

key可以用来检查一篇英文文章单词拼写是否正确:将词库中所有单词放入二叉搜索树,读取文章中的单词,查找是否在二叉搜索树中,不在则波浪线标红提示。

    7.2 key/value搜索场景

每一个关键码key,都有与之对应的值value,value可以为任意类型对象。树的结构中除了需要存储key还要存储对应的value。key/value的搜索场景支持修改,但还是不支持修改key。

 key/value可以统计一篇文章中单词出现的次数:读取一个单词,查找单词是否存在不存在这个说明第一次出现,(单词,1),单词存在,则++单词对应的次数。

     7.3 key/value二叉搜索树代码的实现

template<class K,class V>

struct BSNode

{
     K_key;

     V_value;

    BSNode<K,V>*_left;

    BSNode<K,V>*_right;

    BSNode(const K&key,const V& value)

                   : _key(key)

                   ,_value(value)

                   ,_left(nullptr)

                   ,_right(nullptr)

       {}

};

template<class K,class V>

class BSTree

{

      typedef BSNode<K,N> Node;

public:

      BSTree() = default;

      

     BSTree(const BSTree<K, V>& t)
   {
       _root = Copy(t._root);
   }
    BSTree<K, V>& operator=(BSTree<K, V> t)
   {
     swap(_root, t._root);
     return *this;
   }
   ~BSTree()
   {
      Destroy(_root);
      _root = nullptr;
   }
   
   
   bool Insert(const K& key, const V& value)
{
    if (_root == nullptr)
{
    _root = new Node(key, value);
    return true;
}
   Node* parent = nullptr;
   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;
    }
}
    cur = new Node(key, value);
   if (parent->_key < key)
{
   parent->_right = cur;
}
  else
{
    parent->_left = cur;
}
    return true;
}
Node* Find(const K& key)
{
    Node* cur = _root;
    while (cur)
{
   if (cur->_key < key)
  {
   cur = cur->_right;
  }
 else if (cur->_key > key)
  {
   cur = cur->_left;
  }
else
  {
  return cur;
  }
}
  return nullptr;
}
 
bool Erase(const K& key)
{
     Node* parent = nullptr;
     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
{
  if (cur->_left == nullptr)
    {
      if (parent == nullptr)
     {
       _root = cur->_right;
     }
     else
    {
      if (parent->_left == cur)
      parent->_left = cur->_right;
      else
      parent->_right = cur->_right;
    }
      delete cur;
      return true;
    }
   else if (cur->_right == nullptr)
  {
     if (parent == nullptr)
   {
     _root = cur->_left;
   }
    else
  {
    if (parent->_left == cur)
    parent->_left = cur->_left;
   else
   parent->_right = cur->_left;
  }
   delete cur;
   return true;
}
else
 {
    
   Node* rightMinP = cur;
   Node* rightMin = cur->_right;
    while (rightMin->_left)
{
   rightMinP = rightMin;
   rightMin = rightMin->_left;
}
cur->_key = rightMin->_key;
if (rightMinP->_left == rightMin)
rightMinP->_left = rightMin->_right;
else
rightMinP->_right = rightMin->_right;
 
delete rightMin;
return true;
  }
 }
}
return false;
}
void InOrder()
{
    _InOrder(_root);
    cout << endl;
}
 private:
void _InOrder(Node* root)
{
   if (root == nullptr)
  {
    return;
  }
   _InOrder(root->_left);
  cout << root->_key << ":" << root->_value << endl;
   _InOrder(root->_right);
}
void Destroy(Node* root)
{
if (root == nullptr)
       return;
Destroy(root->_left);
Destroy(root->_right);
delete root;
}
 
Node* Copy(Node* root)
{
   if (root == nullptr)
      return nullptr;
  Node* newRoot = new Node(root->_key, root->_value);
  newRoot->_left = Copy(root->_left);
  newRoot->_right = Copy(root->_right);
   return newRoot;
}
private:
   Node* _root = nullptr;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值