二叉搜索樹---遞歸及非遞歸

二叉搜索樹又稱爲二叉排序樹,它爲一棵空樹,或者是一棵左子樹所有節點的值比根節點小,右子樹所有節點的值比根節點大的一棵樹。

性質:
①.二叉搜索樹中,最左邊的結點值最小,最右邊的結點值最大
②中序遍歷一棵二叉搜索樹,所有節點的值是按順序排列的

   構造一棵二叉搜索樹時,比較插入結點的key值,key小於根節點的_key時,向根節點的左邊走,大於根節點的_key值時,向根節點的右邊走;
   刪除二叉搜索樹中的某個結點時,分爲四種情況;

刪除二叉搜索樹中某個節點的情況及處理方法如下:

這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

二叉搜索樹的基本操作代碼如下:

BSTree.hpp

#pragma once
#include<iostream>
using namespace std;
#include<assert.h>

template<class k,class v>
struct BSNode
{
    BSNode(const k& key,const v& value)
        :_pLeft(NULL)
        ,_pRight(NULL)
        ,_key(key)
        ,_value(value)
    {}

    BSNode<k,v>* _pLeft;
    BSNode<k,v>* _pRight;

    k _key;
    v _value;
};

template<class k,class v>
class BSTree
{
    typedef BSNode<k,v> Node;
public:
    BSTree()
        :_pRoot(NULL)
    {}
    ~BSTree()
    {
        _DestroyBSTree(_pRoot);
    }
    BSTree<k,v>& operator=(const BSTree<k,v>& bst)
    {
        if(this!=&bst)
        {
            _DestroyBSTree(_pRoot);
            _pRoot=_CopyBSTree(bst._pRoot);
        }
        return *this;
    }

    Node* Find(const k& key)//查找某個節點--非遞歸
    {
        Node* pCur=_pRoot;
        while(pCur)
        {
            if(key==pCur->_key)
                return pCur;
            else if(key<pCur->_key)
                pCur=pCur->_pLeft;
            else
                pCur=pCur->_pRight;
        }
        return NULL;
    }

    bool Insert(const k& key,const v& value)//插入某個節點--非遞歸
    {
        if(NULL==_pRoot)
        {
            _pRoot=new Node(key,value);
            return true;
        }
        Node* pCur=_pRoot;
        Node* pParent=NULL;
        while(pCur)
        {
            if(key < pCur->_key)//向左插入
            {
                pParent=pCur;
                pCur=pCur->_pLeft;
            }
            else if(key > pCur->_key)//向右插入
            {
                pParent=pCur;
                pCur=pCur->_pRight;
            }
            else//等於根節點,不需要插入
            {
                return false;
            }
        }
        //插入到葉子結點後時
        pCur=new Node(key,value);
        if(key<pParent->_key)
            pParent->_pLeft=pCur;
        else
            pParent->_pRight=pCur;
        return true;
    }
    void InOrder()//中序遍歷
    {
        cout<<"InOrder:"<<endl;
        _InOrder(_pRoot);
        cout<<endl;
    }
    const k& GetMaxKey()const//找最右結點(最大)
    {
        assert(_pRoot);
        Node* pCur=_pRoot;
        while(pCur->_pRight)
            pCur=pCur->_pRight;
        return pCur->_key;
    }
    const k& GetMinKey()const//找最左結點(最小)
    {
        assert(_pRoot);
        Node* pCur=_pRoot;
        while(pCur->_pLeft)
            pCur=pCur->_pLeft;
        return pCur->_key;
    }

    bool Remove(const k& key)//刪除key結點--非遞歸
    {
        //樹爲空,不能刪除結點
        if(NULL==_pRoot)
            return false;
        //只有一個根節點,要刪除的結點正好是根節點
        if(NULL==_pRoot->_pLeft && NULL==_pRoot->_pRight && key==_pRoot->_key)
        {                                                                     
            delete _pRoot;
            _pRoot=NULL;
            return true;
        }

        //找待刪除結點
        Node* pCur=_pRoot;
        Node* pParent=NULL;
        while(pCur)
        {
            if(key<pCur->_key)
            {
                pParent=pCur;
                pCur=pCur->_pLeft;
            }   
            else if(key>pCur->_key)
            {
                pParent=pCur;
                pCur=pCur->_pRight;
            }       
            else
                break;//找到了該節點
        }
        //已找到待刪除結點---》1.沒有左孩子,只有右孩子
                             //2.沒有右孩子,只有左孩子
                            // 3.左右孩子都沒有
                             //4.左右孩子都存在
                             //可以合併1,3 或2,3
        if(pCur)
        {   //1.沒有左孩子,右孩子可能存在,也可能不存在(NULL)
            if(NULL==pCur->_pLeft)
            {
                if(pCur!=_pRoot)
                {
                    if(pCur==pParent->_pRight)
                        pParent->_pRight=pCur->_pRight;
                    else
                        pParent->_pLeft=pCur->_pRight;
                }
                else
                    _pRoot=pCur->_pRight;
            }
            //2.沒有右孩子,左孩子可能存在,也可能不存在(NULL)
            else if(NULL==pCur->_pRight)
            {
                if(pCur!=_pRoot)
                {
                    if(pCur==pParent->_pRight)
                        pParent->_pRight=pCur->_pLeft;
                    else
                        pParent->_pLeft=pCur->_pLeft;
                }
                else
                    _pRoot=pCur->_pLeft;
            }
            //3.左右子樹都存在
            else
            {
                //找中序遍歷的第一個節點,爲右子樹中最小的結點
                //pParnet一直是firstInOrder的雙親
                pParent=pCur;//防止在找右子樹中最小結點時,右子樹沒有左孩子,無法進入循環,pParent會一直爲空
                Node* firstInOrder=pCur->_pRight;
                //找該節點的右子樹中最左邊的結點,即右子樹中key最小的結點
                while(firstInOrder->_pLeft)
                {
                    pParent=firstInOrder;
                    firstInOrder=firstInOrder->_pLeft;
                }
                //交換key最小結點和根節點的值
                pCur->_key=firstInOrder->_key;
                pCur->_value=firstInOrder->_value;
                if(pParent->_pLeft==firstInOrder)
                    pParent->_pLeft=firstInOrder->_pRight;
                else
                    pParent->_pRight=firstInOrder->_pRight;
                pCur=firstInOrder;
            }
            delete pCur;
            pCur=NULL;
            return true;
        }
        return false;
    }
//遞歸版本
    //Node* Find(const k& key)//遞歸找結點
    //{
    //  Node* pCur=NULL;
    //  pCur=_Find(_pRoot,key);
    //  cout<<pCur->_key<<endl;
 //       return pCur;
    //}

 //   bool Insert(const k& key,const v& value)//遞歸插入
    //{
 //       return _Insert(_pRoot,key,value);
    //}

    //bool Remove(const k& key)//遞歸刪除
    //{
 //       return _Remove(_pRoot,key);
    //}

protected:
    Node* _CopyBSTree(Node* pRoot)//拷貝
    {
        Node* pNewRoot=NULL;
        if(pRoot)
        {
            //拷貝根節點
            pNewRoot=new Node(pRoot->_value);
            //拷貝左子樹
            pNewRoot->_pLeft=_CopyBSTree(pRoot->_pLeft);
            //拷貝右子樹
            pNewRoot->_pRight=_CopyBSTree(pRoot->_pRight);
        }
        return pNewRoot;
    }

    void _DestroyBSTree(Node* &pRoot)
    {
        if(pRoot)
        {
            _DestroyBSTree(pRoot->_pLeft);
            _DestroyBSTree(pRoot->_pRight);
            delete pRoot;
            pRoot=NULL;
        }
    }

    void _InOrder(Node* pRoot)
    {
        if(pRoot)
        {
            _InOrder(pRoot->_pLeft);
            cout<<pRoot->_key<<" ";
            _InOrder(pRoot->_pRight);
        }
    }

 //   Node* _Find(Node* pRoot,const k& key)//遞歸找
    //{
    //  if(NULL==pRoot)
    //      return NULL;
    //  if(key==pRoot->_key)
    //      return pRoot;
    //  else if(key<pRoot->_key)
    //      return _Find(pRoot->_pLeft,key);
    //  else
    //      return _Find(pRoot->_pRight,key);
    //}
    //bool _Insert(Node*& pRoot,const k& key,const v& value)//遞歸插入
    //{
    //  if(NULL==pRoot)
    //  {
    //      pRoot=new Node(key,value);
    //      return true;
    //  }
    //  if(key<pRoot->_key)
    //      return _Insert(pRoot->_pLeft,key,value);
    //  else if(key>pRoot->_key)
    //      return _Insert(pRoot->_pRight,key,value);
    //  else 
    //      return false;
    //}

    //bool _Remove(Node*& pRoot,const k& key)//遞歸刪除
    //{
    //  if(NULL==pRoot)
    //      return false;
    //  else
    //  {
    //      if(key<pRoot->_key)
    //          _Remove(pRoot->_pLeft,key);
    //      else if(key>pRoot->_key)
    //          _Remove(pRoot->_pRight,key);
    //      else
    //      {
    //          Node* pDel=pRoot;
    //          if(NULL==pRoot->_pLeft)
    //          {
    //              pRoot=pRoot->_pRight;
    //              delete pDel;
    //              return true;
    //          }
    //          else if(NULL==pRoot->_pRight)
    //          {
    //              pRoot=pRoot->_pLeft;
    //              delete pDel;
    //              return true;
    //          }
    //          else
    //          {
    //              Node* firstInOrder=pRoot->_pRight;
    //              while(firstInOrder->_pLeft)//找要刪除結點的右子樹中最小結點進行交換
    //                  firstInOrder=firstInOrder->_pLeft;
    //              pDel->_key=firstInOrder->_key;
    //          
    //              return _Remove(pRoot->_pRight,firstInOrder->_key);
    //          }
    //      }
    //  }
    //  return false;
    //}
private:
    Node* _pRoot;
};

測試代碼:
BST.cpp

#include"BSTree.hpp"

void Test1()
{
    BSTree<int,int> bst;
    int a[]={5,3,4,1,7,8,2,6,0,9};
    for(int idx=0;idx<(sizeof(a)/sizeof(a[0]));++idx)
    {
        bst.Insert(a[idx],idx);
    }
    bst.InOrder();
    bst.Find(8);
    cout<<bst.GetMinKey()<<endl;
    cout<<bst.GetMaxKey()<<endl;
}

void Test2()//情況三①②及情況一
{
    BSTree<int,int> bst;
    int a[]={5,3,4,1,7,8,2,6,0,9};
    //int a[]={5,3,4,1,8,2,6,7,0,9};
    for(int idx=0;idx<(sizeof(a)/sizeof(a[0]));++idx)
    {
        bst.Insert(a[idx],idx);
    }
    bst.Remove(8);
    bst.InOrder();
    bst.Remove(6);
    bst.InOrder();

}
void Test3()//情況三中的③
{
    BSTree<int,int> bst;
    int a[]={5,7,8,6,9};
    for(int idx=0;idx<(sizeof(a)/sizeof(a[0]));++idx)
    {
        bst.Insert(a[idx],idx);
    }
    bst.Remove(5);
    bst.InOrder();
}

void Test4()//情況二
{
    BSTree<int,int> bst;
    int a[]={5,3,4,1,7,6,0};
    for(int idx=0;idx<(sizeof(a)/sizeof(a[0]));++idx)
    {
        bst.Insert(a[idx],idx);
    }
    bst.Remove(1);
    bst.InOrder();
    bst.Remove(7);
    bst.InOrder();

}


void Test5()//情況四
{
    BSTree<int,int> bst;
    int a[]={5,3,4,1,7,8,2,6,0,9};
    for(int idx=0;idx<(sizeof(a)/sizeof(a[0]));++idx)
    {
        bst.Insert(a[idx],idx);
    }
    bst.Remove(5);
    bst.InOrder();
    bst.Remove(7);
    bst.InOrder();

}
void Test6()//情況四
{
    BSTree<int,int> bst;
    int a[]={5,3,4,1,7,8,2,0,9};
    for(int idx=0;idx<(sizeof(a)/sizeof(a[0]));++idx)
    {
        bst.Insert(a[idx],idx);
    }
    bst.Remove(5);
    bst.InOrder();
}
int main()
{
    Test1();
    //Test2();
    //Test3();
    //Test4();
    //Test5();
    //Test6();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章