二叉搜索樹又稱爲二叉排序樹,它爲一棵空樹,或者是一棵左子樹所有節點的值比根節點小,右子樹所有節點的值比根節點大的一棵樹。
性質:
①.二叉搜索樹中,最左邊的結點值最小,最右邊的結點值最大
②中序遍歷一棵二叉搜索樹,所有節點的值是按順序排列的構造一棵二叉搜索樹時,比較插入結點的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;
}