二叉搜索树
概念
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
从图中可以直观看见,右子树节点值大于左子树节点值,且中序遍历是按一定顺序排列。
原理
二叉排序树的查找过程和次优二叉树类似,通常采取二叉链表作为二叉排序树的存储结构。中序遍历二叉排序树可得到一个关键字的有序序列,一个无序序列可以通过构造一棵二叉排序树变成一个有序序列,构造树的过程即为对无序序列进行排序的过程。每次插入的新的结点都是二叉排序树上新的叶子结点,在进行插入操作时,不必移动其它结点,只需改动某个结点的指针,由空变为非空即可。搜索,插入,删除的复杂度等于树高,O(log(n)).
操作
template<class T>//定义结点的结构体
struct Node
{
typedef struct Node* _pNode;
_pNode _pRight;
_pNode _pLeft;
T _data;
public:
Node(T data)
:_pRight(NULL)
,_pLeft(NULL)
{
_data = data;
}
Node()
:_pRight(NULL)
,_pLeft(NULL)
{
_data = T();
}
};
1.插入
先判断插入节点值大于根节点,若大于插入右子树,小于插入左子树。
//非递归
bool _Insert(const T data)
{
_pNode pCur = _Root;
_pNode pParent = NULL;
if(_Root != NULL)
{
while(pCur)
{
pParent = pCur;
if(pCur->_data > data)
{
pCur = pCur->_pLeft;
}
else if(pCur->_data < data)
{
pCur = pCur->_pRight;
}
else
{
return false;
}
}
if(pParent != NULL)
{
if(pParent->_data < data)
{
pParent->_pRight = new _Node(data);
}
else
{
pParent->_pLeft = new _Node(data);
}
return true;
}
return false;
}
else
{
_Root = new _Node(data);
return true;
}
}
//递归
bool Insert(const T data)
{
return _recInsert(_Root, data);
}
bool _recInsert(_pNode& pCur, const T data)
{
if(pCur == NULL)
{
pCur = new _Node(data);
return true;
}
if(pCur->_data > data)
{
return _recInsert(pCur->_pLeft, data);
}
else if(pCur->_data < data)
{
return _recInsert(pCur->_pRight, data);
}
else
{
return false;
}
}
2.查找
原理:类似于插入
//非递归
_pNode _find(const T& data)
{
_pNode pCur = _Root;
while(pCur)
{
if(pCur->_data == data)
return pCur;
else if(pCur->_data > data)
{
pCur = pCur->_pLeft;
}
else
{
pCur = pCur->_pRight;
}
}
return NULL;
}
//递归
_pNode Find(const T data)
{
return _recFind(_Root, data);
}
_pNode _recFind(_pNode& pCur, const T data)
{
if(pCur->_data == data)
{
return pCur;
}
if(pCur->_data > data)
{
return _recFind(pCur->_pLeft, data);
}
else if(pCur->_data < data)
{
return _recFind(pCur->_pRight, data);
}
else
{
return NULL;
}
}
3.删除
删除分为三种情况:
1.删除仅有左子树节点;
2.删除仅有右子树节点;
3.删除既有左子树又有右子树节点;
其中叶子节点的情况可包含在1或者2情况中;
**********************************************************************************
1.删除仅有左子树节点:
当删除C节点时,可以直接将指向C的节点直接指向C的左子树;
2.删除仅有右子树节点:
当删除I节点时,可以直接将指向I的节点直接指向I的右子树;
3.删除既有左子树又有右子树节点:
a.删除左子树上的结点(例如D)
保存D的左子树,指向D的结点指向D的右子树,在让现在D的左子树的叶子节点指向之前保存D的左子树。
b.删除右子树上的结点(例如H)
保存H的右子树,指向H的结点指向H的右子树,在让现在H的左子树的叶子节点指向之前保存H的左子树。
c.删除根结点(例如F)
保存F的左子树,根节点变成根节点的右子树,在让现在F的左子树的叶子节点指向之前保存F的左子树。
//非递归
bool _delete(const T& data)
{
_pNode pCur = _Root;
_pNode pParent = NULL;
while(pCur)
{
if(pCur->_data < data)
{
pParent = pCur;
pCur = pCur->_pRight;
}
else if(pCur->_data > data)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else
{
break;
}
}
if(pCur == NULL)
{
return false;
}
if(pCur->_pRight == NULL)
{
pParent->_pLeft = pCur->_pLeft;
delete pCur;
}
else if(pCur->_pLeft == NULL)
{
pParent->_pRight = pCur->_pRight;
delete pCur;
}
else
{
if(pParent != NULL)
{
if(pParent->_pLeft->_data == data)
{
pParent->_pLeft = pCur->_pRight;
}
else
{
pParent->_pRight = pCur->_pRight;
}
_pNode tempLeft = pCur->_pLeft;
_pNode newdel = pCur->_pRight;
while(newdel->_pLeft != NULL)
{
newdel = newdel->_pLeft;
}
newdel->_pLeft = tempLeft;
delete pCur;
}
else
{
_pNode tempLeft = pCur->_pLeft;
_Root = _Root->_pRight;
_pNode tempRight = _Root;
while(tempRight->_pLeft != NULL)
{
tempRight = tempRight->_pLeft;
}
tempRight->_pLeft = tempLeft;
delete pCur;
}
}
}
//递归
bool Delete(const T data)
{
return _recDelete(_Root, data);
}
bool _recDelete(_pNode& pCur, const T data)
{
if(pCur->_data == data)
{
if(NULL == pCur->_pRight)
{
_pNode del = pCur;
pCur = pCur->_pLeft;
delete pCur;
return true;
}
else if(NULL == pCur->_pLeft)
{
_pNode del = pCur;
pCur = pCur->_pRight;
delete pCur;
return true;
}
else
{
_pNode del = pCur->_pRight;
while(del->_pLeft)
{
del = del->_pLeft;
}
pCur->_data = del->_data;
return _recDelete(pCur->_pRight, del->_data);
}
}
if(pCur->_data > data)
{
return _recDelete(pCur->_pLeft, data);
}
else if(pCur->_data < data)
{
return _recDelete(pCur->_pRight, data);
}
else
{
return false;
}
}
完整代码:
#include <iostream>
using namespace std;
template<class T>
struct Node
{
typedef struct Node* _pNode;
_pNode _pRight;
_pNode _pLeft;
T _data;
public:
Node(T data)
:_pRight(NULL)
,_pLeft(NULL)
{
_data = data;
}
Node()
:_pRight(NULL)
,_pLeft(NULL)
{
_data = T();
}
};
template<class T>
class BSTree
{
typedef struct Node<T> _Node;
typedef struct Node<T>* _pNode;
public:
BSTree()
{
_Root = NULL;
}
void _Inorder()
{
Inorder(_Root);
}
//非递归
bool _Insert(const T data)
{
_pNode pCur = _Root;
_pNode pParent = NULL;
if(_Root != NULL)
{
while(pCur)
{
pParent = pCur;
if(pCur->_data > data)
{
pCur = pCur->_pLeft;
}
else if(pCur->_data < data)
{
pCur = pCur->_pRight;
}
else
{
return false;
}
}
if(pParent != NULL)
{
if(pParent->_data < data)
{
pParent->_pRight = new _Node(data);
}
else
{
pParent->_pLeft = new _Node(data);
}
return true;
}
return false;
}
else
{
_Root = new _Node(data);
return true;
}
}
//非递归
_pNode _find(const T& data)
{
_pNode pCur = _Root;
while(pCur)
{
if(pCur->_data == data)
return pCur;
else if(pCur->_data > data)
{
pCur = pCur->_pLeft;
}
else
{
pCur = pCur->_pRight;
}
}
return NULL;
}
//非递归
bool _delete(const T& data)
{
_pNode pCur = _Root;
_pNode pParent = NULL;
while(pCur)
{
if(pCur->_data < data)
{
pParent = pCur;
pCur = pCur->_pRight;
}
else if(pCur->_data > data)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else
{
break;
}
}
if(pCur == NULL)
{
return false;
}
if(pCur->_pRight == NULL)
{
pParent->_pLeft = pCur->_pLeft;
delete pCur;
}
else if(pCur->_pLeft == NULL)
{
pParent->_pRight = pCur->_pRight;
delete pCur;
}
else
{
if(pParent != NULL)
{
if(pParent->_pLeft->_data == data)
{
pParent->_pLeft = pCur->_pRight;
}
else
{
pParent->_pRight = pCur->_pRight;
}
_pNode tempLeft = pCur->_pLeft;
_pNode newdel = pCur->_pRight;
while(newdel->_pLeft != NULL)
{
newdel = newdel->_pLeft;
}
newdel->_pLeft = tempLeft;
delete pCur;
}
else
{
_pNode tempLeft = pCur->_pLeft;
_Root = _Root->_pRight;
_pNode tempRight = _Root;
while(tempRight->_pLeft != NULL)
{
tempRight = tempRight->_pLeft;
}
tempRight->_pLeft = tempLeft;
delete pCur;
}
}
}
//递归
bool Insert(const T data)
{
return _recInsert(_Root, data);
}
_pNode Find(const T data)
{
return _recFind(_Root, data);
}
bool Delete(const T data)
{
return _recDelete(_Root, data);
}
private:
bool _recDelete(_pNode& pCur, const T data)
{
if(pCur->_data == data)
{
if(NULL == pCur->_pRight)
{
_pNode del = pCur;
pCur = pCur->_pLeft;
delete pCur;
return true;
}
else if(NULL == pCur->_pLeft)
{
_pNode del = pCur;
pCur = pCur->_pRight;
delete pCur;
return true;
}
else
{
_pNode del = pCur->_pRight;
while(del->_pLeft)
{
del = del->_pLeft;
}
pCur->_data = del->_data;
return _recDelete(pCur->_pRight, del->_data);
}
}
if(pCur->_data > data)
{
return _recDelete(pCur->_pLeft, data);
}
else if(pCur->_data < data)
{
return _recDelete(pCur->_pRight, data);
}
else
{
return false;
}
}
_pNode _recFind(_pNode& pCur, const T data)
{
if(pCur->_data == data)
{
return pCur;
}
if(pCur->_data > data)
{
return _recFind(pCur->_pLeft, data);
}
else if(pCur->_data < data)
{
return _recFind(pCur->_pRight, data);
}
else
{
return NULL;
}
}
bool _recInsert(_pNode& pCur, const T data)
{
if(pCur == NULL)
{
pCur = new _Node(data);
return true;
}
if(pCur->_data > data)
{
return _recInsert(pCur->_pLeft, data);
}
else if(pCur->_data < data)
{
return _recInsert(pCur->_pRight, data);
}
else
{
return false;
}
}
private:
void Inorder(_pNode pCur)
{
if(!pCur)
return;
Inorder(pCur->_pLeft);
cout<<pCur->_data<<" ";
Inorder(pCur->_pRight);
}
private:
_pNode _Root;
};
void TestFun()
{
BSTree<int> tree;
tree.Insert(5);
tree.Insert(3);
tree.Insert(4);
tree.Insert(2);
tree.Insert(1);
tree.Insert(7);
tree.Insert(6);
tree.Insert(8);
tree.Insert(9);
tree._Inorder();
cout<<endl;
tree.Delete(3);
tree._Inorder();
cout<<endl;
}
int main()
{
TestFun();
return 0;
}