前言
本节内容介绍二叉树的升级版-----二叉搜索树。本节内容比较少,却是后面内容的重要铺垫。
一,二叉搜索树的概念
1.1 二叉搜索树的性质
二叉搜索树又称为二叉排序树,它是一颗空树或具有以下性质的二叉树。
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值。
- 若他的右子树不为空,则右子树上所有节点的值都大于根节点的值。
- 它的左右子树也分别为二叉搜索树。
1.2 二叉搜索树的操作
1. 二叉搜索树的查找
如果根节点不为空:
如果根节点key==查找key 返回true
如果根节点key>查找key 在其左子树查找
如果根节点key<查找key 在其右节点查找
否则 返回false
2.二叉搜索树的插入
a. 树为空,则直接插入
b. 树不空,按二叉搜索树性质查找插入位置,插入新节点
3.二叉搜索树的删除
首先查找元素是否在二叉树中,如果不存在,则返回,否则要删除的结点可能分为下面四种情况:
a.要删除的结点无孩子结点
b.要删除的结点只有左孩子结点
c.要删除的结点只有右孩子结点
d.要删除的结点有左右孩子结点
看起来有四种情况,其实a可以与情况b,c合并起来,因此真正的删除过程如下:
情况b : 删除该结点且使被删除结点的双亲结点指向被删除结点的左孩子结点。
情况c : 删除该结点且使被删除结点的双亲结点指向被删除结点的右孩子结点
情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除结点中,再来处理该节点的删除问题
1.3 二叉搜索树的实现
#include <iostream>
using namespace std;
template<class T>
struct BSTNode
{
BSTNode(const T& x = T())
: left(nullptr)
, right(nullptr)
, data(x)
{}
BSTNode<T>* left;
BSTNode<T>* right;
T data;
};
// 假设:树中节点的值域唯一
template<class T>
class BinarySearchTree
{
typedef BSTNode<T> Node;
public:
BinarySearchTree()
: root(nullptr)
{}
~BinarySearchTree()
{
Destroy(root);
}
bool Insert(const T& data)
{
// 1. 空树---
// 新插入的节点应该是跟节点
if (nullptr == root)
{
root = new Node(data);
return true;
}
// 2. 树非空
// a. 找待插入节点在树中的位置--->按照二叉搜索树的性质
Node* cur = root;
Node* parent = nullptr;
while (cur)
{
parent = cur;
if (data < cur->data)
cur = cur->left;
else if (data > cur->data)
cur = cur->right;
else
return false;
}
// 树中不存在值为data的节点
// b. 插入新节点
cur = new Node(data);
if (data < parent->data)
parent->left = cur;
else
parent->right = cur;
return true;
}
Node* Find(const T& data)const
{
Node* cur = root;
while (cur)
{
if (data == cur->data)
return cur;
else if (data < cur->data)
cur = cur->left;
else
cur = cur->right;
}
return nullptr;
}
bool Erase(const T& data)
{
// 1. 先找data是否存在
Node* cur = root;
Node* parent = nullptr;
while (cur)
{
parent = cur;
if (data == cur->data)
break;
else if (data < cur->data)
cur = cur->left;
else
cur = cur->right;
}
// 值为data的节点不存在
if (nullptr == cur)
return false;
// 2. 找到值为data的节点,即cur--->将该节点删除掉
// 删除节点并且保存树的关系
// 有些节点可以直接删除,但是有些节点不能直接删除
// 需要对cur子树分情况讨论
// 1. cur是叶子
// 2. cur只有左孩子
// 3. cur只有右孩子
// 4. cur左右孩子均存在
// 经过图解分析发现:
// 情况1实际可以和情况2或者情况3合并起来
if (nullptr == cur->left)
{
// 说明cur可能是叶子节点,也可能是只有右孩子
;
}
else if (nullptr == cur->right)
{
// 说明cur只有左孩子
}
else
{
// 说明cur左孩孩子均存在
}
return true;
}
void InOrder()
{
_InOrder(root);
cout << endl;
}
private:
void _InOrder(Node* proot)
{
if (proot)
{
_InOrder(proot->left);
cout << proot->data << " ";
_InOrder(proot->right);
}
}
void Destroy(Node*& proot)
{
if (proot)
{
Destroy(proot->left);
Destroy(proot->right);
delete proot;
proot = nullptr;
}
}
private:
BSTNode<T>* root;
};
void TestBSTree()
{
BinarySearchTree<int> t;
int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
for (auto e : a)
t.Insert(e);
t.InOrder();
BSTNode<int>* cur = t.Find(9);
if (cur)
{
cout << "9 is in BSTree" << endl;
}
else
{
cout << "9 is not in BSTree" << endl;
}
cur = t.Find(13);
if (cur)
{
cout << "13 is in BSTree" << endl;
}
else
{
cout << "13 is not in BSTree" << endl;
}
}
1.4 二叉搜索树的性能分析
最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:log2N
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N/2
总结
以上是就是本文内容,千里之行始于足下,坚持住兄弟们。