二叉排序樹

二叉排序樹

二叉排序樹是爲了實現數據的有序排列,並可方便的對樹中的數據進行插入和刪除操做,提升查找效率。ios

二叉樹

性質:c++

  • 若它的左子樹不爲空,則左子樹上的全部值均小於根結點的值
  • 若它的右子樹不爲空,則右子樹上的全部值均大於根結點的值
  • 它的左右子樹也分別爲二叉排序樹

下面說說二叉排序樹的查找,插入,刪除操做實現。函數

二叉排序樹的結點結構:this

template<class T>
class BTNode
{
public:
    //數據域
    T data;
    //指針域
    BTNode<T> *lchild,*rchild;
public:
    //構造函數
    BTNode(T D,BTNode<T> *l = NULL,BTNode<T> *r=NULL) : data(D),lchild(l),rchild(r) {}
};

查找

二叉排序樹是一個有序的二叉樹,其左子樹永遠比根節點的值小,右子樹用於比根節點的值大。所以咱們可使用遞歸技術,若是key<p->data,則在p的左子樹裏面繼續尋找;若key>p->data則在p的右子樹裏面繼續尋找;直到key=p->data;不然表示未搜索到,退出函數。實現過程以下圖:spa

查找

代碼實現3d

/*
一、在rt中遞歸查找key是否存在,若不存在返回false
二、f指向rt結點的雙親,若rt爲根節點,則f=NULL
三、若key存在,則返回true,p指向該數據值爲key的結點
四、若key不存在,返回false,p指向訪問的最後一個節點
*/
    bool SearchBST(BTNode<T> *rt, T key, BTNode<T> *&p = NULL, BTNode<T> *f = NULL)
    {
        if (!rt) //查找失敗
        {
            p = f;
            return false;
        }
        else if (key == rt->data) //查找成功
        {
            p = rt;
            return true;
        }
        else if (key > rt->data)
        {
            return SearchBST(rt->rchild, key, p, rt); //在右子樹繼續查找
        }
        else
        {
            return SearchBST(rt->lchild, key, p, rt); //在左子樹繼續查找
        }
    }

收穫:函數的參數列表如有指針,而且調用函數時,用的就是一個指針進行傳遞,則進行的是值傳遞。而*&a能夠避免這種現象,這時進行的是地址傳遞。指針

插入

插入的關鍵是,在插入元素後還要繼續保持二叉樹的有序性。實現過程以下圖:code

插入

代碼實現:blog

/*
一、先搜索二叉樹rt中是否存在值key
二、若存在則返回false,不存在則插入
*/
    bool Insert(BTNode<T> *&rt, T key)
    {
        BTNode<T> *p = NULL;
        if (!this->SearchBST(rt, key, p))//未存在key
        {
            BTNode<T> *s = new BTNode<T>(key, NULL, NULL);
            if (!p)//p爲空,即根節點爲空
            {
                rt = s;//令根結點等於s
            }
            else if (key < p->data)
            {
                p->lchild = s;//key小於p->data,將p的左孩子置爲s
            }
            else
            {
                p->rchild = s;//key大於p->data,將p的右孩子置爲s
            }
            return true;
        }
        else
        {
            return false;
        }
    }

刪除

二叉排序樹的難點是刪除操做。排序

刪除結點分三種狀況:

  • 結點沒有左右孩子;
  • 結點只有左子樹或右子樹;
  • 結點左右子樹均有;

結點沒有左右孩子:

解決辦法:刪除該結點,將該結點的雙親指針域置爲NULL

結點只有左子樹或右子樹:

解決辦法:刪除該結點,將該結點的雙親指針域指向該結點的左子樹或右子樹。

結點左右子樹均有:

解決辦法:保留該結點,將該結點的數據域改成該結點直接前驅(或直接後繼)結點的值,刪除該結點的直接前驅結點。

實現過程以下圖:

刪除

代碼實現:

/*
若二叉樹rt中存在key,在刪除結點,並返回true,不然返回false
*/    
	bool DeleteBST(BTNode<T> *&rt,T key)//地址傳遞
    {
        if(!rt)
        {
            //未找到
            return false;
        }
        else
        {
            if(rt->data==key)
            {
                //找到key
                return Delete(rt);//rt只是其雙親指針域的一個別名
            }
            else if (rt->data>key)
            {
                return DeleteBST(rt->lchild,key);
            }
            else
            {
                return DeleteBST(rt->rchild,key);
            }
        }
    }

Delete函數實現:

bool Delete(BTNode<T> *&p)//地址傳遞,p只是別名
    {
        BTNode<T> *q;
        //只存在右子樹,或右子樹也不存在
        if(!p->lchild)
        {
            q=p;
            p=p->rchild;//重接其右子樹
            delete q;//刪除原來的結點
        }
        //只存在左子樹
        else if (!p->rchild)
        {
            q=p;
            p=p->lchild;
            delete q;
        }
        //左右子樹均存在
        else
        {
            BTNode<T> *s=p;
            q=p->lchild;
            //尋找其直接前驅結點
            while(q->rchild)
            {
                s=q;//s爲q的雙親
                q=q->rchild;
            }
            //將q的值賦給p
            p->data=q->data;
            if(s!=p)//若p和q的雙親指向不等
            {
                s->rchild=q->lchild;//重接s的右子樹
            }
            else
            {
                s->lchild=q->lchild;//重接s的左子樹
            }
            delete q;            
        }
        return true;
    }

C++代碼實現:

#include <iostream>
using namespace std;

//二叉樹結點
template <class T>
struct BTNode
{
    T data;                     //存儲數據
    BTNode<T> *lchild, *rchild; //左右孩子指針
    BTNode(T D, BTNode<T> *l = NULL, BTNode<T> *r = NULL) : data(D), lchild(l), rchild(r) {}
};

//二叉樹
template <class T>
class BST
{
    //屬性值
private:
    //根節點指針
    BTNode<T> *root;
    //查找結點
    bool SearchBSTP(BTNode<T> *rt, T key, BTNode<T> *&p = NULL, BTNode<T> *f = NULL)
    {
        if (!rt) //查找失敗
        {
            p = f;
            return false;
        }
        else if (key == rt->data) //查找成功
        {
            p = rt;
            return true;
        }
        else if (key > rt->data)
        {
            return SearchBSTP(rt->rchild, key, p, rt); //在右子樹繼續查找
        }
        else
        {
            return SearchBSTP(rt->lchild, key, p, rt); //在左子樹繼續查找
        }
    }
    //插入結點
    bool Insert(BTNode<T> *&rt, T key)
    {
        BTNode<T> *p = NULL;
        if (!this->SearchBSTP(rt, key, p))
        {
            BTNode<T> *s = new BTNode<T>(key, NULL, NULL);
            if (!p)
            {
                rt = s;
            }
            else if (key < p->data)
            {
                p->lchild = s;
            }
            else
            {
                p->rchild = s;
            }
            return true;
        }
        else
        {
            return false;
        }
    }
    //刪除結點
    bool Delete(BTNode<T> *&p)
    {
        BTNode<T> *q;
        if(!p->lchild)
        {
            q=p;
            p=p->rchild;
            delete q;
        }
        else if (!p->rchild)
        {
            q=p;
            p=p->lchild;
            delete q;
        }
        else
        {
            BTNode<T> *s=p;
            q=p->lchild;
            while(q->rchild)
            {
                s=q;
                q=q->rchild;
            }
            p->data=q->data;
            if(s!=p)
            {
                s->rchild=q->lchild;
            }
            else
            {
                s->lchild=q->lchild;
            }
            delete q;            
        }
        return true;
    }

    bool DeleteBSTP(BTNode<T> *&rt,T key)
    {
        if(!rt)
        {
            //未找到
            return false;
        }
        else
        {
            if(rt->data==key)
            {
                //找到key
                return Delete(rt);
            }
            else if (rt->data>key)
            {
                return DeleteBSTP(rt->lchild,key);
            }
            else
            {
                return DeleteBSTP(rt->rchild,key);
            }
        }
    }
    //中序遍歷
    void InOrder(BTNode<T> *rt)
    {
        if(rt)
        {
            InOrder(rt->lchild);
            cout<<rt->data<<" ";
            InOrder(rt->rchild);
        }
    }
    //刪除二叉樹
    void Destory(BTNode<T> *&rt)
    {
        if(rt)
        {
            Destory(rt->lchild);
            Destory(rt->rchild);
            delete rt;
        }
    }
    //行爲屬性
public:
    //構造函數
    BST(BTNode<T> *r = NULL) : root(r) {}
    //拷貝構造函數
    BST(const BST<T> &bt) : root(NULL)
    {
    }
    //刪除二叉樹
    void Destory()
    {
        this->Destory(this->root);
        this->root=NULL;
    }
    //析構函數
    ~BST()
    {
        this->Destory();
    }
    //得到根指針
    BTNode<T> *Getroot()
    {
        return this->root;
    }
    //搜索值
    //並將
    bool SearchBST(T key, BTNode<T> *p = NULL)
    {
        return this->SearchBSTP(this->root, key, p, NULL);
    }
    //插入結點,順序插入
    /*一、先判斷此值是否存在,若存在,則返回true
      二、若不存在,創造結點s,並順序插入二叉樹中
      三、若不存在,則存在指針p指向查找路徑的最後一個結點
      四、判斷插入值和指針p指向的值的大小,若key>p->data,則p->rchild=s;
                                      不然p->lchild=s;
    */
    bool InsertBST(T key)
    {
        return this->Insert(this->root, key);
    }
    //shanchujiedian
    bool DeleteBST(T key)
    {
        return this->DeleteBSTP(this->root, key);
    }

    void InOrder()
    {
        this->InOrder(this->root);
    }
};

int main()
{
    BST<int> temp;
    int a[] = {62,58,88,47,73,99,35,51,93,29,37,49,56,36,48,50};
    for (int i = 0; i < 16; i++)
    {
        temp.InsertBST(a[i]);
    }
    temp.InOrder();
    cout<<endl;
    //BTNode<int> *p;
    cout << "查找結果:" << temp.SearchBST(51) << endl;
    temp.DeleteBST(62);
    cout << "查找結果:" << temp.SearchBST(50) << endl;
    temp.InOrder();
    cout<<endl;
    temp.Destory();
    temp.InOrder();
    cout<<endl;

    system("pause");
    return 0;
}
相關文章
相關標籤/搜索