二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

平均情况下插入查找删除元素是Onlgn,最差情况下是On的

为什么要实现二叉搜索树?

由二叉搜索树发展来的红黑树是set/map的底层容器,为了学习的梯度我们先基于二叉搜索树来完成set和map。

二叉搜索树的结点设计

	template<typename T>
struct BSnode
{
BSnode():left(nullptr),parent(nullptr),right(nullptr){}
T data;
struct BSnode* parent;
struct BSnode* left;
struct BSnode* right;
};

二叉搜索树的迭代器设计

	template<typename T>
class BStree_base_iterator : public bidirectional_iterator<T>
{
public:
typedef BSnode<T>* ptr;
ptr node;
BStree_base_iterator()
{
node = nullptr;
}
BStree_base_iterator(ptr p)
{
node = p;
}
void increment()
{
if (node->right == nullptr)
{
ptr pre = node->parent;
//回溯 在这里node==pre->right 等价于 node>pre
while (pre != nullptr&&node == pre->right)
{
node = pre;
pre = node->parent;
}
if (pre == nullptr)
node = nullptr;
else
node = pre;
}
else//下一个结点是比自己大的结点(右子树)中最小的(最左)
{
node = node->right;
while (node->left)
node = node->left;
}
}
void decrement()
{
if (node->left == nullptr)
{
ptr pre = node->parent;
while (pre != nullptr&&node == pre->left)
{
node = pre;
pre = node->parent;
}
if (pre == nullptr)
node = nullptr;
else
node = pre;
}
else
{
node = node->left;
while (node->right)
node = node->right;
//return node;
}
}
};
template<typename T>
class BStree_iterator //加一层封装
{
public:
typedef BSnode<T>* ptr;
typedef BStree_iterator<T> self;
BStree_base_iterator<T> p;
BStree_iterator()
{
p.node = nullptr;
}
BStree_iterator(ptr _p)
{
p.node = _p;
}
self& operator++(int)
{
p.increment();
return *this;
}
self& operator--(int)
{
p.decrement();
return *this;
}
bool operator!=(const BStree_iterator<T>& rhs)
{
return !(*this == rhs);
}
bool operator==(const BStree_iterator<T>& rhs)
{
return this->p.node == rhs.p.node;
}
T& operator*()
{
return p.node->data;
}
T& operator->()
{
return &(*this);
}
};

二叉搜索树源码

插入删除查找元素都可以利用和节点的值进行比较来递归查找,为了避免stackoverflow可以使用递归函数的非递归形式

	template<typename T >
class BStree
{
public:
typedef T value_type;
typedef T* pointer;
typedef size_t size_type;
typedef BSnode<T>* node_ptr;
typedef BStree<T> self;
typedef BStree_iterator<T> iterator;
private:
// Compare comparator;
node_ptr node;
size_t data_cnt;//元素个数
std::allocator<BSnode<T>> data_allocator;
node_ptr new_node(const value_type& val,node_ptr pre)//建立新节点
{
node_ptr p = data_allocator.allocate(1);
new(&p->data) value_type(val);
p->left = nullptr;
p->right = nullptr;
p->parent = pre;
return p;
}
node_ptr insert_aux(node_ptr p, node_ptr pre,const value_type& val, node_ptr& ret)
{
while (p)
{
if (p->data == val) return p;
pre = p;
p = p->data > val ? p->left : p->right;
}
return new_node(val, pre); /* 递归版本 数目太多会stackoverflow
if(!p)
{
return ret = new_node(val, pre);
}
if (p->data > val)
p->left = insert_aux(p->left, p, val, ret);
else if (p->data < val)
p->right = insert_aux(p->right, p, val, ret);
else
ret = p;
return p;*/
}
iterator find_aux(node_ptr p, const value_type& val)
{
while (p && p->data != val)
{
p = p->data > val ? p->left : p->right;
}
return iterator(p);
}
void del()
{
ministl::queue<node_ptr> q;
q.push(node);
while (!q.empty())
{
node_ptr p = q.front();
q.pop();
if (p->left)
{
q.push(p->left);
}
if (p->right)
{
q.push(p->right);
}
//删除之前保证左右子树入队 否则会有内存泄露
delete p;
}
node = nullptr;
} //删除操作,分四种情况
//1. 左右子树为空,删除结点 并且将其父节点对应指针设置为空即可
//2. 左子树空 右不空 删除结点 并且将其父节点对应指针设置为右子树即可
//3. 左不空 右空 删除结点 并且将其父节点对应指针设置为左子树即可
//4. 左右不空 找到左子树中值最大的元素 和结点元素交换
void erase_aux(node_ptr p)
{
if (p->left == nullptr&&p->right == nullptr)
{
if (p->parent == nullptr)
{
node = nullptr;
}
else if (p->parent->left!=nullptr && p->parent->left->data == p->data)
p->parent->left = nullptr;
else if (p->parent->right!=nullptr && p->parent->right->data == p->data)
p->parent->right = nullptr;
delete(p);
}
else if (p->left == nullptr&&p->right != nullptr)
{
if (p->parent == nullptr)
{
node = p->right,node->parent = nullptr;
}
else if (p->parent->left!=nullptr && p->parent->left->data == p->data)
p->parent->left = p->right, p->right->parent = p->parent;
else if (p->parent->right!=nullptr && p->parent->right->data == p->data)
p->parent->right = p->right, p->right->parent = p->parent;
delete(p);
}
else if (p->left != nullptr&&p->right == nullptr)
{
if (p->parent == nullptr)
{
node = p->left, node->parent = nullptr;
}
else if (p->parent->left!=nullptr && p->parent->left->data == p->data)
p->parent->left = p->left, p->left->parent = p->parent;
else if (p->parent->right!=nullptr && p->parent->right->data == p->data)
p->parent->right = p->left, p->left->parent = p->parent;
delete(p);
}
else
{
node_ptr it = p->left;
node_ptr tmp = p;
while (it->right != nullptr)
{
tmp = it, it = it->right;
}
p->data = it->data;
if (tmp != p)
{
tmp->right = it->left;
}
else
{
tmp->left = it->left;
}
if (it->left != nullptr)
it->left->parent = tmp;
delete(it);
}
}
iterator lower_bound_aux(node_ptr p, const value_type& x)
{
if (!p)
return iterator(nullptr);
if (p->data >= x)
{
auto tmp = lower_bound_aux(p->left, x);
if (tmp.p.node != nullptr)
return tmp;
else
return iterator(p);
}
else
return lower_bound_aux(p->right, x);
}
iterator upper_bound_aux(node_ptr p, const value_type& x)
{
if (!p)
return iterator(nullptr);
if (p->data > x)
{
auto tmp = upper_bound_aux(p->left, x);
if (tmp.p.node != nullptr)
return tmp;
else
return iterator(p);
}
else
return upper_bound_aux(p->right, x);
}
void erase_val_aux(node_ptr p,const value_type& key)
{
if (p == nullptr)
return;
if (p->data == key)
erase_aux(p);
else if (p->data < key)
erase_val_aux(p->right, key);
else if (p->data > key)
erase_val_aux(p->left, key);
}
public:
BStree() :node(nullptr),data_cnt(0) {}
bool empty()
{
return node == nullptr;
}
size_type size()
{
return data_cnt;
}
iterator begin()
{
if (node == nullptr)
{
iterator t(nullptr);
return t;
}
iterator it(node);
while (it.p.node->left != nullptr)
it.p.node = it.p.node->left;
return it;
}
iterator end()
{
iterator it(nullptr);
return (it);
}
iterator find_max()
{
node_ptr p = node;
if (p == nullptr)
return iterator(nullptr);
while (p->right != nullptr)
p = p->right;
return iterator(p);
}
node_ptr root()
{
return node;
}
pair<iterator,bool> insert(const value_type& val)
{
node_ptr ret = nullptr;
node = insert_aux(node, nullptr, val, ret);
data_cnt++;
return make_pair<iterator, bool>(ret , ret == nullptr);
}
iterator find(const value_type& key)
{
return find_aux(node, key);
}
iterator lower_bound(const value_type& x)
{
return lower_bound_aux(node, x);
}
iterator upper_bound(const value_type& x)
{
return upper_bound_aux(node, x);
}
void erase(iterator pos)
{
erase_aux(pos.p.node);
data_cnt--;
}
void erase(const value_type& x)
{
erase_val_aux(node, x);
data_cnt--;
}
void clear()
{
del();
data_cnt = 0;
}
};

从零开始写STL-二叉搜索树的更多相关文章

  1. javascript数据结构——写一个二叉搜索树

    二叉搜索树就是左侧子节点值比根节点值小,右侧子节点值比根节点值大的二叉树. 照着书敲了一遍. function BinarySearchTree(){ var Node = function(key) ...

  2. 手写AVL平衡二叉搜索树

    手写AVL平衡二叉搜索树 二叉搜索树的局限性 先说一下什么是二叉搜索树,二叉树每个节点只有两个节点,二叉搜索树的每个左子节点的值小于其父节点的值,每个右子节点的值大于其左子节点的值.如下图: 二叉搜索 ...

  3. 二叉搜索树的两种实现(数组模拟,STL)

    书上实现: 二叉搜索数的特点:高效实现 插入一个数值,查询是否包含某个数值,删除某一个数值. 所有的节点都满足左子树上的所有节点都比自己的小,而右子树上的所有节点都比自己大的特点. 查询:如果当前数值 ...

  4. CF 675D——Tree Construction——————【二叉搜索树、STL】

    D. Tree Construction time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  5. [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法

    二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...

  6. 二叉搜索树、AVL平衡二叉搜索树、红黑树、多路查找树

    1.二叉搜索树 1.1定义 是一棵二叉树,每个节点一定大于等于其左子树中每一个节点,小于等于其右子树每一个节点 1.2插入节点 从根节点开始向下找到合适的位置插入成为叶子结点即可:在向下遍历时,如果要 ...

  7. [LeetCode] Serialize and Deserialize BST 二叉搜索树的序列化和去序列化

    Serialization is the process of converting a data structure or object into a sequence of bits so tha ...

  8. [LeetCode] Validate Binary Search Tree 验证二叉搜索树

    Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as ...

  9. [LeetCode] Unique Binary Search Trees 独一无二的二叉搜索树

    Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For examp ...

  10. PAT树_层序遍历叶节点、中序建树后序输出、AVL树的根、二叉树路径存在性判定、奇妙的完全二叉搜索树、最小堆路径、文件路由

    03-树1. List Leaves (25) Given a tree, you are supposed to list all the leaves in the order of top do ...

随机推荐

  1. Oracle创建用户及权限设置

    oracle用户创建及权限设置 权限: create session create table unlimited tablespace connect resource dba 例: #sqlplu ...

  2. 洛谷 P1030 求先序排列

    题目描述 给出一棵二叉树的中序与后序排列.求出它的先序排列.(约定树结点用不同的大写字母表示,长度<=8). 输入输出格式 输入格式: 2行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序 ...

  3. (译文)IOS block编程指南 4 声明和创建blocks

    Declaring and Creating Blocks (声明和创建blocks) Declaring a Block Reference (声明一个block引用) Block variable ...

  4. type和isinstance区别

    type只能对类型做直接的判断,主要用于获取未知变量的类型. 在程序中几乎很少用到type. 而isinstance功能比type更强,可以对子类型做出推理判断. isinstance主要用于判断A是 ...

  5. Django-常用设置(settings.py)

    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 当前项目的根目录,Django会依此来定位工程内的相关文件 ...

  6. 位(bit)、字节(byte)、字

    1.位(bit)来自英文bit,音译为“比特”,表示二进制位.位是计算机内部数据储存的最小单位,11010100是一个8位二进制数.一个二进制位只可以表示0和1两种状态(21):两个二进制位可以表示0 ...

  7. Vue项目结构梳理

    Vue项目结构图: 简单介绍目录结构 build目录是一些webpack的文件,配置参数什么的,一般不用动 config是vue项目的基本配置文件 node_modules是项目中安装的依赖模块 sr ...

  8. No-1.文件和目录

    文件和目录 01. 单用户操作系统和多用户操作系统(科普) 单用户操作系统:指一台计算机在同一时间 只能由一个用户 使用,一个用户独自享用系统的全部硬件和软件资源 Windows XP 之前的版本都是 ...

  9. 找回Settings Sync的gist id和token

    方法一:如果你本地有缓存参考:https://www.cnblogs.com/zhang1028/p/9514471.html 方法二:如果你电脑重装系统了 1.找回gist id 登陆你的githu ...

  10. canvas使用自定义字体没有效果

    字体样式没有显示主要是因为字体还没有加载完成~ css @font-face { font-family: myFont; src: local('sen.ttf'), url("sen.t ...