理论基础 —— 查找 —— 二叉排序树
【概述】
二叉排序樹(Binary Search Tree),又稱二叉查找樹,其本質(zhì)是按一定的順序進(jìn)行構(gòu)造的二叉樹。
其遞歸定義如下:
- 若其左子樹不空,則左子樹上所有結(jié)點(diǎn)的值均小于根結(jié)點(diǎn)的值
- 若其右子樹不空,則右子樹上所有結(jié)點(diǎn)的值均大于根節(jié)點(diǎn)的值
- 其左右子樹也是二叉排序樹
從上述定義可以看出,二叉排序樹是記錄之間滿足一定次序的二叉樹,中序遍歷二叉排序樹可以得到一個(gè)按關(guān)鍵碼有序的序列。
折半查找判定樹就是一棵二叉排序樹:點(diǎn)擊這里
【實(shí)現(xiàn)類】
template<class T> struct Node{T data;Node *lchild,*rchild; }; template<class T> class BiSortTree{ public:BiSortTree(T a[],int n);//構(gòu)造函數(shù)~BiSortTree(){release(root);}//析構(gòu)函數(shù)void insertBST(Node<T> *&root,Node<T> *s);//插入結(jié)點(diǎn)void deleteBST(Node<T> *p,Node<T> *f);//刪除結(jié)點(diǎn)Node<T> *searchBST(Node<T> *bt,int k);//查找結(jié)點(diǎn) private:Node<T> *root;//指向根節(jié)點(diǎn)的頭指針void release(Node<T> *bt);//析構(gòu)函數(shù)調(diào)用 };【插入操作】
根據(jù)二叉排序樹的定義,向二叉排序樹中插入一個(gè)結(jié)點(diǎn) s 的過程可用如下偽代碼描述:
從上述插入過程可以看出,插入的結(jié)點(diǎn)是作為葉結(jié)點(diǎn)插入到二叉排序樹中的,其過程是遞歸進(jìn)行的。
template<class T> void BiSortTree<T>::insertBST(Node<T> *&root,Node<T> *s) {if(root==NULL)root=s;else if(s->data<root->data)insertBST(root->lchild,s);elseinsertBST(root->rchild,s); }【構(gòu)造函數(shù)】
構(gòu)造二叉排序樹的過程是從空的二叉排序樹開始,依次插入一個(gè)個(gè)結(jié)點(diǎn),其構(gòu)造過程可用如下偽代碼描述:
依次取每一個(gè)記錄 a[i],進(jìn)行如下操作:
1)申請(qǐng)一個(gè)數(shù)據(jù)域?yàn)?a[i] 的結(jié)點(diǎn) s,令結(jié)點(diǎn) s 的左右指針域?yàn)榭?/p>
2)調(diào)用插入操作的方法,將結(jié)點(diǎn) s 插入二叉排序樹中
template<class T> BiSortTree<T>::BiSortTree(T a[],int n){for(int i=0;i<n;i++){Node<T> *s;s->data=a[i];s->lchild=NULL;s->rchild=NULL;insertBST(root,s);} }【刪除操作】
在二叉排序樹中,由于刪除結(jié)點(diǎn)時(shí),刪除的可能是葉結(jié)點(diǎn)也可能是分支結(jié)點(diǎn),因此在刪除時(shí),需要重新修改指針,使得刪除一個(gè)結(jié)點(diǎn)后,仍能保證二叉排序樹的特性。
在二叉排序樹中的刪除操作中,設(shè)待刪除結(jié)點(diǎn)為 p,其父結(jié)點(diǎn)為 f,且 p 是 f 的左孩子,那么可分為以下三種情況進(jìn)行討論:
1.p 為葉結(jié)點(diǎn)
當(dāng)被刪除的結(jié)點(diǎn)為葉結(jié)點(diǎn)時(shí),由于刪除后不影響二叉排序樹特性,因此只需將被刪除結(jié)點(diǎn)的父節(jié)點(diǎn) f 的相應(yīng)指針域改為空即可。
如下圖,有:f->lchild=NULL
2.p 只有左子樹 pl 或只有右子樹 pr
當(dāng)被刪除的結(jié)點(diǎn)僅有一棵子樹時(shí),需要將 pl 或 pr 替換為 f 的左子樹。
如下圖,有:f->lchild=p->lchild 或 f->rchild=p-rchild
3.p 既有左子樹又有右子樹
當(dāng)被刪除的結(jié)點(diǎn)有兩棵子樹時(shí),需要找其前驅(qū)(即:大于 p 的最小值 或 小于 p 的最大值)來將其代替,然后刪除該前驅(qū)。
綜上,刪除操作可用如下偽代碼描述:
1.若結(jié)點(diǎn) p 是葉結(jié)點(diǎn),則直接刪除結(jié)點(diǎn) p
2.若結(jié)點(diǎn) p 只有左子樹,則只需重接 p 的左子樹;若結(jié)點(diǎn) p 只有右子樹,則只需重接 p 的右子樹
3.若結(jié)點(diǎn) p 的左右子樹均不空,則:
? 1)查找結(jié)點(diǎn) p 的右子樹上的最左下結(jié)點(diǎn) s 及 s 雙親結(jié)點(diǎn) f
? 2)將結(jié)點(diǎn) s 數(shù)據(jù)域替換到被刪結(jié)點(diǎn) p 的數(shù)據(jù)域
? 3)若結(jié)點(diǎn) p 的右孩子無左子樹,則將 s 的右子樹接到 f 的右子樹上;否則,將 s 的右子樹接到結(jié)點(diǎn) f 的左子樹上
? 4)刪除結(jié)點(diǎn) s?
【查找操作】
由于二叉排序樹的定義,在二叉樹中查找給定值 k 的過程是:
- 若 root 是空樹,查找失敗
- 若 k=root->data,查找成功
- 若 k<root->data,在 root 的左子樹進(jìn)行查找
- 若 k>root->data,在 root 的右子樹進(jìn)行查找
上述過程一直持續(xù)到 k 被找到或者待查找的子樹為空,若待查找的子樹為空,則查找失敗。值得注意的是,當(dāng)查找失敗時(shí),恰好找到了以 k 為鍵值的新結(jié)點(diǎn)在二叉排序樹中的插入位置。
template<class T> Node<T> *BiSortTree<T>::searchBST(Node<T> *bt,int k){if(bt==NULL)return NULL;else if(bt->data==k)return bt;else if(k<bt->data)return searchBST(bt->lchild,k);elsereturn searchBST(bt->rchild,k); }【析構(gòu)函數(shù)】
二叉排序樹的析構(gòu)函數(shù)與二叉鏈表的析構(gòu)函數(shù)相同
template<class T> void BiSortTree<T>::release(Node<T> *bt){if(bt!=NULL){release(bt->lchild);release(bt->rchild);delete bt;} }?
總結(jié)
以上是生活随笔為你收集整理的理论基础 —— 查找 —— 二叉排序树的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 理论基础 —— 索引 —— 2-3 树
- 下一篇: 信息学奥赛一本通(1012:计算多项式的