一、二叉搜索树的性质:
1、每个结点都有一个作为搜索依据的关键码,并且这个关键码是互不相同的
2、左子树上的所有结点的关键码都小于根节点的关键码
3、右子树上的所有结点的关键码都大于根节点的关键码
4、左右子树也是二叉搜索树
例:
二、二叉树搜索树所支持的操作
1、查找
在二叉搜索树上进行查找,是从根节点出根据关键码的大小选择一条分支向下进行查找。一般情况下最多查找树的高度次就能得出结果,所以大多数情况下二叉搜索树的平均查找时间是O(logN)。但是如果删除多的话,二叉搜索树会逐渐向左倾斜,退化成链表,时间复杂度就是O(N).
例:
(1)、查找3
(2)、查找8
(3)、查找最小值
在这棵树不为空的情况下,判断根节点有没有左子树。如果根节点没有左子树的话,则直接返回根节点。如果有左子树的话,则沿左分支查找最后一个数。
Node* _FindMin(Node* cur)
{
assert(cur);
while (cur->_left)
{
cur = cur->_left;
}
return cur;
}
(4)、查找最大值
在这棵树不为空的情况下,判断根节点有没有右子树。如果根节点没有右子树的话,则直接返回根节点。如果有右子树的话,则沿右分支查找最后一个数。
Node* _FindMax(Node* cur)
{
assert(cur);
while (cur->_right)
cur = cur->_right;
return cur;
}
(5)、查找第k个数
Node* _Find(Node* cur,int k)
{
int num =_Size(cur->_left);
if (k == num + 1)
return cur;
else if (k <= num)
{
return _Find(cur->_left,k);
}
else
{
return _Find(cur->_right,k-num-1);
}
}
2、插入
插入一个数使得二叉树仍然是一颗二叉搜索树。从根节点出发搜索插入位置,然后把新节点作为叶子结点插入。这样的话不需要移动结点,只需要修改一个叶子结点的空指针就行。
void _Insert(Node* &cur,const T& x)
{
if (cur == NULL)
{
cur = new Node(x);
return;
}
if (x < cur->_data)
{
_Insert(cur->_left, x);
}
else if (cur->_data < x)
{
_Insert(cur->_right,x);
}
}
例:
3、删除
删除比较复杂一点,但是可以分为两种情况。
(1、假如要删除的结点有两个孩子,则应该将右子树上关键码最小的结点与要删除的结点交换,再删除右子树上关键码最小的那个结点。
例:
(2、假如要删除的结点只有一个孩子
例:
假如只有右孩子或者没有孩子与只有左孩子是相同的道理。
void _Remove(Node* &cur,const T& x)
{
if (cur == NULL)
return;
if (x < cur->_data)
{
_Remove(cur->_left,x);
}
else if (cur->_data < x)
{
_Remove(cur->_right,x);
}
else
{
if (cur->_left != NULL&&cur->_right != NULL) //如果要删除的结点有两个孩子
{
Node* del = cur;
cur->_data =_FindMin(cur->_right)->_data;
_Remove(cur->_right,cur->_data);
}
else //如果要删除的结点是叶子结点或只有一个孩子的结点
{
Node* del = cur;
cur = (cur->_left != NULL) ? cur->_left : cur->_right;
delete del;
}
}
}
#pragma once
#include<cassert>
#include<queue>
using namespace std;
template<typename T>
struct SearchTreeNode
{
SearchTreeNode<T>* _left;
SearchTreeNode<T>* _right;
T _key;
SearchTreeNode(const T& key)
:_left(NULL)
, _right(NULL)
, _key(key)
{}
};
template<typename T>
class BinarySearchTree
{
typedef SearchTreeNode<T> Node;
public:
BinarySearchTree()
:_root(NULL)
{}
BinarySearchTree(T* a,size_t size)
{
_root = NULL;
for (int i = 0; i < (int)size; i++)
{
Insert(a[i]);
}
}
BinarySearchTree(const BinarySearchTree<T>& tree) //拷贝构造
:_root(NULL)
{
if (tree._root == NULL)
return;
queue<Node*> q;
q.push(tree._root);
while (!q.empty())
{
Node* cur = q.front();
Insert(cur->_key);
q.pop();
if (cur->_left)
{
q.push(cur->_left);
}
if (cur->_right)
{
q.push(cur->_right);
}
}
}
~BinarySearchTree()
{
_Destory(_root);
}
BinarySearchTree<T>& operator=(BinarySearchTree<T>& tree) //赋值运算符重载
{
if (this!=&tree)
{
BinarySearchTree<T> tmp(tree);
swap(_root,tmp._root);
}
return *this;
}
bool Insert(const T& x)
{
if (_root == NULL)
{
_root = new Node(x);
return true;
}
Node* cur = _root;
Node* parent =NULL;
while (cur) //找到要插入的位置
{
parent = cur;
if (x > cur->_key) //如果要插入的值大于当前结点
{
cur = cur->_right;
}
else if (x<cur->_key) //如果要插入的值小于当前结点
{
cur = cur->_left;
}
else
{
return false;
}
}
//判断一下x要插入到parent的左边还是右边
if (x>parent->_key) //插入到右边
{
parent->_right = new Node(x);
}
else //插入到左边
{
parent->_left = new Node(x);
}
return true;
}
bool Remove(const T& x)
{
Node* cur=_root;
Node* parent = NULL;
while (cur)
{
if (cur->_key < x)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key>x)
{
parent = cur;
cur = cur->_left;
}
else
{
if (cur->_left == NULL) //如果cur的左孩子为空,或左右都为空
{
if (parent == NULL)
{
_root = cur->_right;
}
else
{
if (parent->_left==cur)
parent->_left = cur->_right;
else
parent->_right = cur->_right;
}
delete cur;
}
else if (cur->_right == NULL) //如果cur的右孩子为空
{
if (parent == NULL)
{
_root = cur->_left;
}
else
{
if (parent->_left == cur)
parent->_left = cur->_left;
else
parent->_right = cur->_left;
}
delete cur;
}
else //如果左右都不为空,寻找cur的右子树的最左结点,与之交换
{
Node* tmp = cur->_right;
Node* prev = cur;
while (tmp->_left)
{
prev= tmp;
tmp =tmp->_left;
}
swap(cur->_key,tmp->_key); //交换着两个结点的值
if (prev->_left == tmp)
{
prev->_left = NULL;
}
else
{
prev->_right = NULL;
}
delete tmp;
}
return true;
}
}
return false;
}
const Node* Find(const T& x)
{
Node* cur = _root;
while (cur)
{
if (cur->_key < x)
{
cur = cur->_right;
}
else if (cur->_key>x)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return cur;
}
protected:
void _Destory(Node* cur)
{
if (cur == NULL)
return;
_Destory(cur->_left);
_Destory(cur->_right);
delete cur;
}
private:
Node* _root;
};