目录
平衡二叉搜索树:AVL树(高度平衡树)、红黑树;
一,二叉搜索树定义
二叉搜索树,又称二叉排序树,是经典的数据结构,既具有链表快速插入和删除的特点,也有顺序表快速查找的特点;通过中序遍历可得到有序序列;
- 或为一颗空树;
- 或具有一下性质的二叉树;
- 若其左子树不为空,则左子树所有节点的值都小于根节点的值;
- 若其右子树不为空,则右子树所有节点的值都大于根节点的值;
- 其左右子树也分别为二叉搜索树;
int arr[] = {5,3,4,1,7,8,2,6,0,9}

二,二叉搜索树操作
- 查找,O(logN),最坏O(N);
- 插入,O(logN);
- 删除,O(logN);
二叉搜索树的查找
从根节点开始,将目标值与当前节点比较,若等于当前节点,则直接返回;若比当前节点小则进入左子树进行比较,否则进入右子树进行比较。重复以上步骤直到找到目标值或遇到空节点停止查找。
if(root)
if(root->data == x)
return true;
if(root->data > x)
在其左子树查找
if(root->data < x)
在其右子树查找
else
return false
二叉搜索树的插入
从根节点开始,将新节点与当前节点比较大小,如果比当前节点小则进入左子树进行比较,否则进入右子树。当到达某个空节点时,将新节点插入到该位置。
- 树为空,则直接插入,然后返回true;
- 树不为空,按二叉搜索树性质查找插入位置,插入新节点;
插入新节点10:
1,按照二叉搜索树的性质,查找插入节点的位置
root-->5 5<10 root=root->right parent=root
root-->7 7<10 root=root->right parent=root
root-->8 8<10 root=root->right parent=root
root-->9 9<10 root=root->right parent=root
2,插入新节点
二叉搜索树的删除
- 首先查找元素是否在二叉搜索树中,如不存在,则返回;
- 否则,要删除的节点可能分为以下四种情况;
- 要删除的节点无孩子,直接删除;
- 要删除的节点只有左或右孩子,将其父节点直接指向左或右孩子;
- 要删除的节点左右孩子节点都有,则在其左子树中找到最大的节点或右子树中找到最小的节点,用其值填补到被删除节点,然后在左子树或右子树中删除这个大的节点或最小节点;
二叉搜索树的实现
template <class T>
struct BSTNode
{
BSTNode(const T& data = T())
:_pleft(nullptr)
,_pright(nullptr)
,_data(data)
{}
BSTNode<T>* _pleft;
BSTNode<T>* _pright;
T _data;
};
template <class T>
class BSTree
{
typedef BSTNode<T> Node;
typedef Node* pNode;
public:
BSTree()
:_pRoot(nullptr)
{}
~BSTree()
{
while (_pRoot)
{
Erase(_pRoot->_data);
}
}
pNode _Find(const T& data, pNode& pCur, pNode& pParent)
{
while (pCur)
{
if (data == pCur->_data)
break;
else if (data < pCur->_data)
{
pParent = pCur;
pCur = pCur->_pleft;
}
else
{
pParent = pCur;
pCur = pCur->_pright;
}
}
return pCur;
}
pNode Find(const T& data)
{
pNode pParent = nullptr;
pNode pCur = _pRoot;
return _Find(data, pCur, pParent);
}
bool Insert(const T& data)
{
if (_pRoot == nullptr)
{
_pRoot = new Node(data);
return true;
}
pNode pParent = nullptr;
pNode pCur = _pRoot;
while (pCur)
{
pParent = pCur;
if (data < pCur->_data)
pCur = pCur->_pleft;
else if (data > pCur->_data)
pCur = pCur->_pright;
else
return false;
}
pCur = new Node(data);
if (data < pParent->_data)
pParent->_pleft = pCur;
else
pParent->_pright = pCur;
return true;
}
bool Erase(const T& data)
{
pNode pParent = nullptr;
pNode pCur = _pRoot;
pNode pdata = _Find(data, pCur, pParent);
if (pdata == nullptr)
return false;
if (pCur->_pleft != nullptr && pCur->_pright != nullptr)
{
pParent = pCur;
pCur = pCur->_pleft;
while (pCur->_pright)
{
pParent = pCur;
pCur = pCur->_pright;
}
}
if (pParent != nullptr)
{
if (pCur->_pright == nullptr)
{
if (pCur->_data < pParent->_data)
pParent->_pleft = pCur->_pleft;
else
pParent->_pright = pCur->_pleft;
}
else if (pCur->_pleft == nullptr)
{
if (pCur->_data < pParent->_data)
pParent->_pleft = pCur->_pright;
else
pParent->_pright = pCur->_pright;
}
pdata->_data = pCur->_data;
}
else
{
if (pCur->_pright == nullptr)
_pRoot = pCur->_pleft;
else
_pRoot = pCur->_pright;
}
delete pCur;
pCur = nullptr;
return true;
}
void _InOrder(const pNode pRoot)
{
pNode pCur = pRoot;
if (pCur == nullptr)
return;
_InOrder(pCur->_pleft);
cout << pCur->_data << " ";
_InOrder(pCur->_pright);
}
void InOrder()
{
_InOrder(_pRoot);
}
private:
pNode _pRoot;
};
//二叉搜索树实现
//节点类型模板
template<class T>
struct BSTNode
{
BSTNode(const T& data=T())
:_pleft(nullptr),_pright(nullptr),_data(data)
{}
BSTNode* _pleft;
BSTNode* _pright;
T _data;
};
//二叉搜索树类型模板
template<class T>
class BSTree
{
typedef BSTNode<T> Node;
typedef Node* pNode;
private:
pNode _pRoot;
public:
//默认成员函数
BSTree()
:_pRoot(nullptr)
{}
~BSTree()
{
while (_pRoot) { Erase(_pRoot->_data); }
}
//成员函数
pNode _Find(const T& data, pNode pCur, pNode pParent)
{
while (pCur)
{
if (data == pCur->_data) break;
else if (data < pCur->_data) //小于就在左节点查找
{
pParent = pCur;
pCur = pCur->_pleft;
}
else //大于就在右节点查找
{
pParent = pCur;
pCur = pCur->_pright;
}
}
return pCur;
}
pNode Find(const T& data)
{
pNode pParent = nullptr;
pNode pCur = _pRoot;
return _Find(data, pCur, pParent);
}
bool Insert(const T& data)
{
if (_pRoot == nullptr)
{
_pRoot = new Node(data);
return true;
}
//根节点不为空,分别与左右子节点比较,直到空为止;
pNode pParent = nullptr;
pNode pCur = _pRoot;
while (pCur)
{
if (data < pCur->_data) //小于就在左节点查找
{
pParent = pCur;
pCur = pCur->_pleft;
}
else if (data > pCur->_data)//大于就在右节点查找
{
pParent = pCur;
pCur = pCur->_pright;
}
else
return false;
}
pCur = new Node(data);
if (pCur->_data < pParent->_data) pParent->_pleft = pCur;
if (pCur->_data > pParent->_data) pParent->_pright = pCur;
return true;
}
bool Erase(const T& data)
{
pNode pParent = nullptr;
pNode pCur = _pRoot;
pNode pdata = _Find(data, pCur, pParent); //更新当前节点和父节点
//未查找到data,直接返回假;
if (pdata == nullptr) return false;
//查找到的当前节点,其左右子节点都不为空时,查找左子节点的最大值;
if (pCur->_pleft != nullptr && pCur->_pright != nullptr)
{
pParent = pCur;
pCur = pCur->_pleft;
while (pCur->_pright) //向下查找,直到右子节点为空
{
pParent = pCur;
pCur = pCur->_pright;
}
}
//父节点不为空
//1,查找到的当前节点,其左右子节点不全都有(无子节点或只有一个子节点,如图片中6或8),将父节点直接连接其子节点;
//2,查找到的当前节点,其左右子节点都有(如图片中3或7),将左子节点的最大值复制给带删除的节点(最后在删除此最大值节点);
if (pParent != nullptr)
{
if (pCur->_pright == nullptr) //当前节点无右子节点
{
if (pCur->_data < pParent->_data) pParent->_pleft = pCur->_pleft;
else pParent->_pright = pCur->_pleft;
}
else if (pCur->_pleft == nullptr)
{
if (pCur->_data < pParent->_data) pParent->_pleft = pCur->_pright;
else pParent->_pright = pCur->_pright;
}
pdata->_data = pCur->_data;
}
//父节点为空,则删除的就是根节点
else
{
if (pCur->_pright == nullptr) _pRoot = pCur->_pleft;
else _pRoot = pCur->_pright;
}
//销毁释放节点
delete pCur;
pCur = nullptr;
return true;
}
void _Inorder(const pNode pRoot)
{
if (pRoot->_pleft)_Inorder(pRoot->_pleft);
cout << pRoot->_data << " ";
if (pRoot->_pright)_Inorder(pRoot->_pright);
}
void Inorder() { _Inorder(_pRoot); }
};
三,二叉搜索树的应用
K模型
- 即只有key作为关键码(关键码即为待搜索的值),结构中只需存储key即可;
- 如,一个单词word,判断该单词是否拼写正确;
- 以单词集合中每个单词为key,构建一颗二叉搜索树;
- 在二叉搜索树中检索该单词是否存在,存在即正确,不存在即错误;
KV模型
- 每一个关键码key,都有与之对应的值Value,即<Key,Value>键值对;
- 该种方式在生活中非常常见,如英汉字典就是中英文对应关系,通过英文可快速找到对应的中文,英文单词与对应中文<word、chinese>构造一种键值对;再比如统计单词次数,统计成功后,给定单词就可快速找到其出现次数,单词与出现次数<word,count>构成一种键值对;
template <class K, class V>
struct BSTNode
{
BSTNode(const K& key = K(), const V& value = V())
: _pleft(nullptr)
, _pright(nullptr)
, _key(key)
, _value(value)
{}
BSTNode<K, V>* _pleft;
BSTNode<K, V>* _pright;
K _key;
V _value;
};
template <class K, class V>
class BSTree
{
typedef BSTNode<K, V> Node;
typedef Node* pNode;
public:
BSTree()
:_pRoot(nullptr)
{}
~BSTree()
{
while (_pRoot)
{
Erase(_pRoot->_key);
}
}
pNode _Find(const K& key, pNode& pCur, pNode& pParent)
{
while (pCur)
{
if (key == pCur->_key)
break;
else if (key < pCur->_key)
{
pParent = pCur;
pCur = pCur->_pleft;
}
else
{
pParent = pCur;
pCur = pCur->_pright;
}
}
return pCur;
}
pNode Find(const K& key)
{
pNode pParent = nullptr;
pNode pCur = _pRoot;
return _Find(key, pCur, pParent);
}
bool Insert(const K& key, const V& value)
{
if (_pRoot == nullptr)
{
_pRoot = new Node(key, value);
return true;
}
pNode pParent = nullptr;
pNode pCur = _pRoot;
while (pCur)
{
pParent = pCur;
if (key < pCur->_key)
pCur = pCur->_pleft;
else if (key > pCur->_key)
pCur = pCur->_pright;
else
return false;
}
pCur = new Node(key, value);
if (key < pParent->_key)
pParent->_pleft = pCur;
else
pParent->_pright = pCur;
return true;
}
bool Erase(const K& key)
{
pNode pParent = nullptr;
pNode pCur = _pRoot;
pNode pdata = _Find(key, pCur, pParent);
if (pdata == nullptr)
return false;
if (pCur->_pleft != nullptr && pCur->_pright != nullptr)
{
pParent = pCur;
pCur = pCur->_pleft;
while (pCur->_pright)
{
pParent = pCur;
pCur = pCur->_pright;
}
}
if (pParent != nullptr)
{
if (pCur->_pright == nullptr)
{
if (pCur->_key < pParent->_key)
pParent->_pleft = pCur->_pleft;
else
pParent->_pright = pCur->_pleft;
}
else if (pCur->_pleft == nullptr)
{
if (pCur->_key < pParent->_key)
pParent->_pleft = pCur->_pright;
else
pParent->_pright = pCur->_pright;
}
pdata->_key = pCur->_key;
}
else
{
if (pCur->_pright == nullptr)
_pRoot = pCur->_pleft;
else
_pRoot = pCur->_pright;
}
delete pCur;
pCur = nullptr;
return true;
}
private:
pNode _pRoot;
};
四,二叉搜索树的性能分析
- 插入和删除操作都必须先查找,查找的效率代表了二叉搜索树中各个操作的性能;
- 对有n个节点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是节点在二叉搜索树的深度的函数,即节点越深,则比较次数越多;
- 但对同一个关键码集合,如各关键码插入的次序不同,可能得到不同结构的二叉搜索树;

最优情况下,二叉搜索树为完全二叉树O(logN),平均比较次数为logN;
最差情况下,二叉搜索树退化为单支树O(N),平均比较次数为N/2;

本文详细介绍了二叉搜索树的基本概念、查找、插入和删除操作,并探讨了其在K模型和KV模型中的应用。二叉搜索树提供高效的查找、插入和删除操作,平均时间复杂度为O(logN)。此外,讨论了二叉搜索树在不同插入顺序下性能的最优与最差情况。
900

被折叠的 条评论
为什么被折叠?



