二叉搜索树
二叉搜索树(Binary Search Tree),任何节点的键值一定大于其左子树中每一个节点的键值,并且小于其右子树中的每一个节点的键值。
二叉搜索树或者是一颗空树,或者是具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上的所有节点的键值小于根节点的键值
- 若它的左子树不为空,则右子树上的所有节点的键值大于根节点的键值
- 它的左右子树也分别为二叉搜索树
插入
- 若树为空,则直接插入
- 若树不为空,从根节点开始,遇到键值较大的则向左,遇到键值较小的则向右,直到尾端,插入新的节点
//非递归插入
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 if (cur->key == key)
{
return false;
}
}
cur = new Node(key);
//插入在左边还是右边
if(parent->key>key)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
return true;
}
//递归插入
bool _InsertR(Node*& root,const K& key)
{
if (root == nullptr)
{
root = new Node(key);
}
if (root->key < key)
{
return _InsertR(root->_right, key);
}
else if (root->key > key)
{
return _InsertR(root->_left, key);
}
else
{
return false;
}
}
bool InsertR(const K& key)
{
return _InsertR(_root, key);
}
删除
首先查找元素是否在二叉树中,如果不存在,则返回,否则要删除的结点分为:
- 删除该节点,并且让被删除节点的双亲节点,指向被删除节点的左孩子节点
- 删除该节点,并且让被删除节点的双亲节点,指向被删除节点的右孩子节点
- 在他的右子树中寻找中序下的第一个结点,用它的键值来填补到被删除节点中,再来处理删除该节点的问题
//非递归删除
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
{
//1、删除的结点只有右孩子
if (cur->_left == nullptr)
{
if (parent == nullptr)
{
_root = cur->_right;
}
else
{
if (cur == parent->_left)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
}
//2、删除的结点只有左孩子
else if (cur->_right == nullptr)
{
if (parent == nullptr)
{
_root = cur->_left;
{
if (cur == parent->_left)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
delete cur;
}
//3、删除的结点左右孩子都有或者都没有
else
{
Node* rightminParent = cur;
Node* rightmin = cur->_right;
//寻找右子树的左孩子
while (rightmin->_left)
{
rightminParent = rightmin;
rightmin = rightmin->_left;
}
swap(cur->key, rightmin->key);
if (rightminParent->_right == rightmin)
{
rightminParent->_right = rightmin->_right;
}
else
{
rightminParent->_left = rightmin->_right;
}
delete rightmin;
}
return true;
}
}
return false;
}
//递归的删除
bool _EraseR(Node*& cur,const K& key)
{
if(cur==nullptr)
{
return false;
}
if(cur->key<key)
{
return _EraseR(cur->_right,key);
}
else if(cur->key>key)
{
return _EraseR(cur->_left,key);
}
else if(cur->key==key)
{
//1、左为空
//2、右为空
//3、左右都不为空
Node* del=cur;
if(cur->_left==nullptr)
{
cur=cur->_right;
delete del;
return true;
}
else if(cur->_right==nullptr)
{
cur=cur->_left;
delete del;
return true;
}
else
{
//替换删除法,左子树的最大节点或者 右子树的最小节点
Node* minNode=cur->_right;
while(minNode->_left)
{
minNode=minNode->left;
}
cur->key=minNode->key;
//转换成删除右子树的最小节点
return _EraseR(cur->_right,minNode->key);
}
}
}
bool EraseR(const K& key)
{
return _EraseR(_root,key);
}
搜索
根据二叉树的性质进行搜索:
- 如果目标值等于节点的值,则返回节点
- 如果目标值小于节点的值,则继续在左子树中搜索
- 如果目标值大于节点的值,则继续在右子树中搜索
//非递归查找
Node* Find(const K& key)
{
Node* cur=_root;
//遍历二叉树
while(cur)
{
if(cur->key>key)
{
cur=cur->_left;
}
else if(cur->key<key)
{
cur=cur->_right;
}
else if(cur->key==key)
{
return cur;
}
}
//如果没有找到返回nullptr
return nullptr;
}
//递归查找
Node* FindR(const K& key)
{
return _FindR(_root,key);
}
Node* _FindR(Node* root,const K& key)
{
if(root==nullptr)
{
return nullptr;
}
if(root->key>key)
{
return _FindR(root->_left,key);
}
else if(root->key<key)
{
return _FindR(root->_right,key);
}
else if(root->key==key)
{
return root;
}
}
模拟实现
#pragma once
#include<iostream>
using namespace std;
//二叉树的节点
template<class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;//左节点
BSTreeNode<K>* _right;//右节点
K key;//节点的key
//构造函数
BSTreeNode(const K& key)
:_left(nullptr)
,_right(nullptr)
,key(key)
{
}
};
//K->key
template<class K>
//Binary Search Tree
class BSTree
{
typedef BSTreeNode<K> Node;
public:
//插入
bool insert(const K& key)
{
//如果二叉树为空
if (_root == nullptr)
{
//创建一个节点作为根节点
_root = new Node(key);
return true;
}
//二叉树不为空
//定义parent指针,用来指向cur的根节点
Node* parent = nullptr;
//定义cur指针指当前节点
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->key == key)
{
return false;
}
}
//找到插入的位置,将key放入
cur = new Node(key);
//如果要插入位置的跟节点大于key
if(parent->key>key)
{
//插入的节点做左节点
parent->_left = cur;
}
else
{
parent->_right = cur;
}
return true;
}
//递归插入
bool _InsertR(Node*& root,const K& key)
{
if (root == nullptr)
{
root = new Node(key);
}
if (root->key < key)
{
return _InsertR(root->_right, key);
}
else if (root->key > key)
{
return _InsertR(root->_left, key);
}
else
{
return false;
}
}
bool InsertR(const K& key)
{
return _InsertR(_root, key);
}
//查找
Node* Find(const K& key)
{
//定义cur节点指针指向根节点
Node* cur = _root;
//遍历二叉搜索树
while (cur)
{
//如果当前节点的值大于要找的值
if (cur->key > key)
{
//当前节点的左子树寻找
cur = cur->_left;
}
//如果当前节点的值小于于要找的值
else if (cur->key < key)
{
//当前节点的右子树寻找
cur = cur->_right;
}
//如果当前节点的值等于要找的值
else if (cur->key == key)
{
//找到,返回节点指针
return cur;
}
}
//遍历完还没有找到,返回空
return nullptr;
}
//递归查找
Node* _FindR(Node* root, const K& key)
{
if (root == nullptr)
{
return nullptr;
}
if (root->key > key)
{
return _FindR(root->_left, key);
}
else if (root->key < key)
{
return _FindR(root->_right, key);
}
else if (root->key == key)
{
return root;
}
}
Node* FindR(const K& key)
{
return _FindR(_root, key);
}
//递归的删除
bool _EraseR(Node*& cur, const K& key)
{
if (cur == nullptr)
{
return false;
}
if (cur->key < key)
{
return _EraseR(cur->_right, key);
}
else if (cur->key > key)
{
return _EraseR(cur->_left, key);
}
else if (cur->key == key)
{
//1.左为空,2.右为空,3.左右都不为空
Node* del = cur;
if (cur->_left == nullptr)
{
cur = cur->_right;
delete del;
return true;
}
else if (cur->_right == nullptr)
{
cur = cur->_left;
delete del;
return true;
}
else
{
//替换法删除,左树的最大节点或者右树的最小节点
Node* minNode = cur->_right;
while (minNode->_left)
{
minNode = minNode->_left;
}
cur->key = minNode->key;
//转化成删除右子树的最小节点
return _EraseR(cur->_right,minNode->key);
}
}
}
bool EraseR(const K& key)
{
return _EraseR(_root,key);
}
//删除
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 (cur == parent->_left)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr)
{
if (parent == nullptr)
{
_root = cur->_left;
}
else
{
if (cur == parent->_left)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
delete cur;
}
}
else
{
Node* rightminParent = cur;
Node* rightmin = cur->_right;
while (rightmin->_left)
{
rightminParent = rightmin;
rightmin = rightmin->_left;
}
swap(cur->key, rightmin->key);
if (rightminParent->_right == rightmin)
{
rightminParent->_right = rightmin->_right;
}
else
{
rightminParent->_left = rightmin->_right;
}
delete rightmin;
}
return true;
}
}
return false;
}
//中序遍历
void _Inorder(Node* root)
{
if(root==nullptr)
{
return;
}
_Inorder(root->_left);
cout << root->key << " ";
_Inorder(root->_right);
}
void Inorder()
{
_Inorder(_root);
cout << endl;
}
private:
Node* _root = nullptr;
};