竹杖芒鞋_

二叉查找树BinarySearchTree(BST)类模板的实现

一、基础理论

1.树

  • 没有儿子的节点称为树叶,具有相同父亲的节点为兄弟。
  • 对任意节点ki,ki的深度为从根到k的唯一路径长,即根的深度为0。节点k的高是从k到一片树叶的最长路径的长。
  • 一个结点拥有孩子的个数称为该结点的度,树中各结点度的最大值称为该树的度。
  • 一棵树是N个节点和N-1条边的集合

2.二叉树

在这里插入图片描述
重要性质:

  • 二叉树中,第 i 层最多有 2i-1 个结点。

  • 如果二叉树的深度为 K,那么此二叉树最多有 2K-1 个结点。

  • 二叉树中,终端结点数(叶子结点数)为 n0,度为 2 的结点数为 n2,则 n0=n2+1。
    证明:在这里插入图片描述

  • 每一棵具有N个节点的二叉树都需要N+1个nullptr链。
    证明:每棵二叉树共有2N个链域,其中除根节点外每个节点都有父节点,即共有N-1个指针指向某个节点,空指针为2N-(N-1)=N+1。

  • 如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树。

  • 满二叉树中第 i 层的节点数为 2n-1 个。

  • 具有 n 个节点的满二叉树的深度为 log2(n+1)。

3. 完全二叉树

如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。在这里插入图片描述

  • n 个结点的完全二叉树的深度为 ⌊log2n⌋+1。
  • 对于任意一个完全二叉树来说,如果将含有的结点按照层次从左到右依次标号(如图 a)完全二叉树),对于任意一个结点 i ,完全二叉树还有以下几个结论成立:
  1. 当 i>1 时,父亲结点为结点 [i/2] 。(i=1 时,表示的是根结点,无父亲结点)
  2. 如果 2i>n(总结点的个数) ,则结点 i 肯定没有左孩子(为叶子结点);否则其左孩子是结点 2i 。
  3. 如果 2i+1>n ,则结点 i 肯定没有右孩子;否则右孩子是结点 2i+1 。

4.二叉查找树

使二叉树成为二叉查找树的性质是,对于树中的每个节点X,它的左子树中所有项的值均小于X中的项,而它的右子树中所有项的值均大于X中的项。如:二叉查找树
这样,在有n个元素的该数据结构中查找一个元素的时间复杂度为log2n。

二、 代码实现

#include<ostream>
using namespace std;
template<typename Comparable>
class BinarySearchTree {
private:
struct BinaryNode {
Comparable element;
BinaryNode* left;
BinaryNode* right;
BinaryNode(const Comparable&theElement,BinaryNode*lt,BinaryNode*rt)
:element{theElement},left{lt},right{rt}{}
BinaryNode(Comparable&&theElement,BinaryNode*lt,BinaryNode*rt)
:element{std::move(theElement)},left{lt},right{rt}{}
};
BinaryNode* root;
/**
* 向子树插入元素的内部方法
* x是要插入的项
* t为该子树的根节点
* 置子树的新根
**/
void insert(const Comparable& x, BinaryNode*& t)
{
if (t == nullptr)
t = new BinaryNode{ x,nullptr,nullptr };
else if (x < t->element)
insert(x, t->left);
else if (t->element < x)
insert(x, t->right);
else
; //重复元,什么也不做
}
/**
* 向子树插入元素的内部方法
* x是通过移动实现要插入的项
* t为该子树的根节点
* 置子树的新根
*/
void insert(Comparable&& x, BinaryNode*& t)
{
if (t == nullptr)
t = new BinaryNode{ std::move(x),nullptr,nullptr };
else if (x < t->element)
insert(std::move(x), t->left);
else if (x > t->element)
insert(std::move(x), t->right);
else
; //重复元,什么也不做
}
/**
* 从一棵子树删除一项的内部方法
* 参数x是要被删除的项
* 参数t为该子树的根节点
* 置该子树的新的根
*/
void remove(const Comparable& x, BinaryNode*& t)
{
if (t == nullptr)
return; //项没找到,什么也不做
if (x < t->element)
remove(x, t->left);
else if (t->element < x)
remove(x, t->right);
else if (t->left != nullptr && t->right != nullptr) //有两个儿子
{
t->element = findMin(t->right)->element;
remove(t->element, t->right);
}
else {
BinaryNode* oldNode = t;
t = (t->left != nullptr) ? t->left : t->right;
delete oldNode;
}
}
/**
* 找出子树t中最小项的内部方法
* 返回包含最小项的节点
* 递归实现
*/
BinaryNode* findMin(BinaryNode* t) const
{
if (t == nullptr)
return nullptr;
if (t->left == nullptr)
return t;
return findMin(t->left);
}
/**
* 找出子树t中最大项的内部方法
* 返回包含最大项的节点
* 非递归实现
*/
BinaryNode* findMax(BinaryNode* t) const
{
if (t != nullptr) {
while (t->right != nullptr)
t = t->right;
}
return t;
}
/**
* 测试一项是否在子树上的内部方法
* x是要查找的项
* t是作为该子树的根的节点
*/
bool contains(const Comparable& x, BinaryNode* t) const
{
if (t == nullptr)
return false;
else if (t->element < x) { //x比当前节点大,去右子树找
return contains(x, t->right);
}
else if (t->element > x) { //x比当前节点小,去左子树找
return contains(x, t->left);
}
else
return true; //匹配,找到了
}
/**
* 使子树为空的内部方法
*/
void makeEmpty(BinaryNode*& t)
{
if (t != nullptr) {
makeEmpty(t->left);
makeEmpty(t->right);
delete t;
}
t = nullptr;
}
//以排序顺序打印根在t处的子树的内部方法
void printTree(BinaryNode* t, ostream& out)const
{
if (t != nullptr) {
printTree(t->left, out);
out << t->element << endl;
printTree(t->right, out);
}
}
/**
* 克隆子树的内部方法
*/
BinaryNode* clone(BinaryNode* t)const {
if (t == nullptr)
return nullptr;
else
return new BinaryNode{ t->element,clone(t->left),clone(t->right) };
}
/**
* 计算根在t处子树的高度的内部方法
* 后序遍历计算树的高度
*/
int height(BinaryNode* t)const {
if (t == nullptr) {
return -1;
}
else
return 1 + max(height(t->left), height(t->right));
}
public:
BinarySearchTree() :root{ nullptr } {}
BinarySearchTree(const BinarySearchTree& rhs) :root{ nullptr }
{
root = clone(rhs.root);
}
BinarySearchTree(BinarySearchTree&& rhs) :root{ rhs.root } {
rhs.root = nullptr;
}
~BinarySearchTree() {
makeEmpty();
}
const Comparable& findMin()const {
return findMin(root)->element;
}
const Comparable& findMax()const {
return findMax(root)->element;
}
//如果在树中找到x,则返回true
bool contains(const Comparable& x)const {
return contains(x, root);
}
bool isEmpty()const {
return root == nullptr;
}
int height()const
{
return height(root);
}
//按排列顺序打印树的内容
void printTree(ostream& out)const {
if (isEmpty())
out << "Empty tree" << std::endl;
else
printTree(root, out);
}
void makeEmpty() {
makeEmpty(root);
}
//将x插入到树中,忽略重复元
void insert(const Comparable& x) {
insert(x, root);
}
void insert(Comparable&& x) {
insert(std::move(x), root);
}
//将x从树中删除,若没找到x,则什么也不做
void remove(const Comparable& x) {
remove(x, root);
}
/**
* Copy assignment
*/
BinarySearchTree& operator=(const BinarySearchTree& rhs)
{
BinarySearchTree copy = rhs;
std::swap(*this, copy);
return *this;
}
/**
* Move assignment
*/
BinarySearchTree& operator=(BinarySearchTree&& rhs)
{
std::swap(root, rhs.root);
return *this;
}
};
posted @   aw11  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示