二叉排序樹是爲了實現數據的有序排列,並可方便的對樹中的數據進行插入和刪除操做,提升查找效率。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; }