二叉搜索树,咕咕咕
1.概念
二叉搜索树又叫二叉排序树,或者是一棵空树,也可以是有以下性质的二叉树:
左子树不为空,左子树上所有的点值都小于等于根结点的值。
右子树不为空,右子树上所有的点值都大于等于根结点的值。
它的左右子树也都是二叉搜索树。
二叉搜索树中可以支持插入相同的值,也可以不支持相等的值,map/set/multimap/multiset系列底层容器就是二叉搜索树,map/set不支持插入相等的值,multimap/multiset支持插入相等的值。
2.性能分析
最优情况下:二叉搜索树为完全二叉树,高度log 2 N
最差情况下:退化为单支树,高度为N
综合而言二叉搜索树的增删查改的时间复杂度为O(N),它可以进化成平衡二叉树和红黑树才能适用于在内存中存储和搜索数据
二分查找也可以实现log 2 N 的查找效率,但是有2个缺点:
需要存储在支持下标随机访问的结构中,并且有序。
插入和删除数据效率低,因为存储在下标随机访问的结构中,插入和删除数据一般需要挪动数据。
3.插入
1.树为空,直接新增结点,赋值给root指针
2.树不空,按二叉搜索树,插入值比当前结点大,向右走,插入值比当前结点小,往左走,找到空位置,插入。
3.如果支持插入相同的值,插入值和当前结点相等的值可以往右走,也可以往左走,找到空位置,插入新结点(不要一会向右,一会向左)
4.查找
1.从根开始比较,查找x,x比根值大,向右走,x比根值小,向左走
2.最多查找高度次数,走到空,没找到,就不存在
3.如果不支持插入相等的值,找到x就返回
4.如果支持插入相等的值,意味着有多个x存在,一般要求查找中序的第一个x
5.删除
查找元素是否在二叉搜索树中,不存在的话,返回false
如果存在:
1.删除结点N左右子树都是空(N结点的父结点对应的孩子指针置空,直接删除N结点)
2.删除结点N左子树为空(把N结点的父结点对应的孩子指针指向N的右孩子,直接删除N结点)
3.删除结点N右子树为空(把N结点的父结点对应的孩子指针指向N的左孩子,直接删除N结点)
4。删除结点N左右子树不为空(无法直接删除N结点,找N结点左子树值最大结点R(左子树中最右的)或者右子树值最小的结点(右子树最左的结点)代替N,因为这2个结点中任意一个放到N的位置都满足二叉搜索树的规则,把该结点与N的值交换,转变为删除R结点位置可以直接删除
6.实现的代码
template<class K>
struct BSTNode
{
K key;
BSTNode<K>* left;
BSTNode<K>* right;
BSTNode(const K& key):key(key),left(nullptr),right(nullptr)
{
}
};
template<class K>
class BStree
{
typedef BSTNode<K> Node;
public:
bool Insert(const K& key)
{
if(root==nullptr)
{
root=new Node(key);
return true;
}
Node* parent=nullptr;
Node* cur=root;
while(cur)
{
if(cur->key<key)
{
parent=cur;
cur=cur->right;
}
else if(cur->key>key)
{
parent=cur;
cur=cur->left;
}
else{
return false;
}
}
cur=new Node(key);
if(parent->key<key)
{
parent->right=cur;
}
else{
parent->left=cur;
}
return true;
}bool Find(const K& key)
{
Node* cur=root;
while(cur)
{
if(cur->key<key)
{
cur=cur->right;
}
else if(cur->key<key)
{
cur=cur->left;
}
else{
return true;
}
}
return false;
}bool Erase(const K& key)
{
Node* parent=nullptr;
Node* cur=root;
while(cur)
{
if(cur->key<key)
{
parent=cur;
cur=cur->right;
}
else if(cur->key>key)
{
parent=cur;
cur=cur->left;
}
else{
if(cur->left==nullptr)
{
if(parent==nullptr)
{
root=cur->right;
}
else{
if(parent->left==cur)
parent->left=cur->right;
else
parent->right=cur->right;
}
delete cur;
return true;
}
else if(cur->right==nullptr)
{
if(parent==nullptr)
{
root=cur->left;
}
else{
if(parent->left==cur)
parent->left=cur->left;
else
parent->right=cur->left;
}
delete cur;
return true;
}
else{
Node* rightminp=cur;
Node* rightmin=cur->right;
while(rightmin->left)
{
rightminp=rightmin;
rightmin=rightmin->left;
}
cur->key=rightmin->key;
if(rightminp->left==rightmin)
rightminp->left=rightmin->right;
else
rightminp->right=rightmin->right;
delete rightmin;
return true;
}
}
}
return false;
}void InOrder()
{
_InOrder(root);
cout<<endl;
}
private:
void _InOrder(Node* root)
{
if(root==nullptr)
{
return;
}
_InOrder(root->left);
cout<<root->key<<" ";
_InOrder(root->right);
}
private:
Node* root=nullptr;
};7.二叉搜索树key/value
key搜索场景:只有key作为关键码,结构中只要存储key就行,关键码即为需要搜索到的值,搜索场景只要判断key在不在,key搜索场景实现的二叉搜索树可以增删查,不能改
key/value搜索场景:每一个关键码key都有与之对应的值value,value可以是任意类型对象,树的结构中除了存储key还要存储对应的value,key/value搜索场景实现的二叉搜索树不支持修改key但是可以修改value
template<class K,class V>
struct BSTNode
{
K key;
V value;
BSTNode<K,V>* left;
BSTNode<K,V>* right;
BSTNode(const K& key,const V& value):key(key),value(value),
left(nullptr),right(nullptr)
{
}
};
template<class K,class V>
class BSTree
{
typedef BSTNode<K,V> Node;
public:
BSTree()=default;//让系统生成默认构造
BSTree(const BSTree<K,V>& t)
{
root=Copy(t.root);
}
BSTree<K,V>& operator=(BSTree<K,V> t)
{
swap(root,t.root);
return *this;
}
~BSTree()
{
Destroy(root);
root=nullptr;
}
bool Insert(const K& key,const V& value)
{
if(root==nullptr)
{
root=new Node(key,value);
return true;
}
Node* parent=nullptr;
Node* cur=root;
while(cur)
{
if(cur->key<key)
{
parent=cur;
cur=cur->right;
}
else if(cur->key>key)
{
parent=cur;
cur=cur->left;
}
else{
return false;
}
}
cur=new Node(key,value);
if(parent->key<key)
{
parent->right=cur;
}
else{
parent->left=cur;
}
return true;
}Node* Find(const K& key)
{
Node* cur=root;
while(cur)
{
if(cur->key<key)
{
cur=cur->right;
}
else if(cur->key>key)
{
cur=cur->left;
}
else{
return cur;
}
}
return nullptr;
}bool Erase(const K& key)
{
Node* parent=nullptr;
Node* cur=root;
while(cur)
{
if(cur->key<key)
{
parent=cur;
cur=cur->right;
}
else if(cur->key>key)
{
parent=cur;
cur=cur->left;
}
else{
if(cur->left==nullptr)
{
if(parent==nullptr)
{
root=cur->right;
}
else{
if(parent->left==cur)
parent->left=cur->left;
else
parent->right=cur->right;
}
delete cur;
return true;
}
else if(cur->right==nullptr)
{
if(parent==nullptr)
{
root=cur->left;
}
else{
if(parent->left==cur)
parent->left=cur->left;
else
parent->right=cur->left;
}
delete cur;
return true;
}
else{
Node* rightminp=cur;
Node* rightmin=cur->right;
while(rightmin->left)
{
rightminp=rightmin;
rightmin=rightmin->left;
}
cur->key=rightmin->key;
if(rightminp->left==rightmin)
rightminp->left=rightmin->right;
else
rightminp->right=rightmin->right;
delete rightmin;
return true;
}
}
}
return false;
}void InOrder()
{
_InOrder(root);
cout<<endl;
}
private:
void _InOrder(Node* root)
{
if(root==nullptr)
{
return;
}
_InOrder(root->left);
cout<<root->key<<";"<<root->value<<endl;
_InOrder(root->right);
}
void Destroy(Node* root){
if(root==nullptr)
return;
Destroy(root->left);
Destroy(root->right);
delete root;
}
Node* Copy(Node* root)
{
if(root==nullptr)
return nullptr;
Node* newroot=new Node(root->key,root->value);
newroot->left=Copy(root->left);
newroot->right=Copy(root->right);
return newroot;
}
private:
Node* root=nullptr;
};