二叉查找树(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. Synplify FPGA 逻辑综合

    作为 Synopsys FPGA 设计解决方案的一部分,Synplify FPGA 综合软件是实现高性能.高性价比的 FPGA 设计的行业标准. 其独特的行为提取综合技术 (Behavior Extr ...

  2. 不能说的hidden

    不能说的hidden 时光跑跑...路在脚下...晨光依在...----Vashon 1.所谓"时尚",本质上就是自己看不见自己的样子.好比我们在地球上,却感觉不到地球在动. 2. ...

  3. JS通过使用PDFJS实现基于文件流的预览功能

    需求: 使用JS实现PDF文件预览功能 备选方案: 使用ViewerJS,官网  http://viewerjs.org/ 使用PDFJS,官网  https://mozilla.github.io/ ...

  4. 如何实现Windows宿主系统和虚拟机ubuntu系统文件互相访问

    我的宿主操作系统是Windows 10,使用Oracle的Virtual Box安装了Ubuntu. 因为工作需要我经常得在两个系统之间互相拷贝一些数据,下面是具体步骤,可以实现Windows 10和 ...

  5. Android开发案例 - 淘宝商品详情【转】

    http://erehmi.cnblogs.com/ 所有电商APP的商品详情页面几乎都是和淘宝的一模一样(见下图): 采用上下分页的模式 商品基本参数 & 选购参数在上页展示 商品图文详情等 ...

  6. C-基础:数组名与取地址符&

    指出下面代码的输出,并解释为什么.(不错,对地址掌握的深入挖潜) main() { ]={,,,,}; ); printf(),*(ptr-)); } 输出:2,5     *(a+1)就是a[1], ...

  7. 枚举 || CodeForces 742B Arpa’s obvious problem and Mehrdad’s terrible solution

    给出N*M矩阵,对于该矩阵有两种操作: 1.交换两列,对于整个矩阵只能操作一次 2.每行交换两个数. 交换后是否可以使每行都递增. *解法:N与M均为20,直接枚举所有可能的交换结果,进行判断 每次枚 ...

  8. 在实现栈中原来功能的基础上,获得一个栈中最小值,要求时间复杂度 bigO(1)

    思路: 准备两个栈 stackData stackMin package my_basic; import java.util.Stack; public class GetMinStack { St ...

  9. python3查询Excel中A表在B表没有的数据,并保存到新的Excel,这里用的是“xlrd”和“xlwt”

    import xlrd import xlwt # 打开A表,将A表的数据存放到cols1中,这里打印出来是方便查看测试数据. data1 = xlrd.open_workbook(r'F:\cars ...

  10. js 简单制作键盘模拟

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head& ...