从零开始写STL-二叉搜索树
二叉查找树(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-二叉搜索树的更多相关文章
- javascript数据结构——写一个二叉搜索树
二叉搜索树就是左侧子节点值比根节点值小,右侧子节点值比根节点值大的二叉树. 照着书敲了一遍. function BinarySearchTree(){ var Node = function(key) ...
- 手写AVL平衡二叉搜索树
手写AVL平衡二叉搜索树 二叉搜索树的局限性 先说一下什么是二叉搜索树,二叉树每个节点只有两个节点,二叉搜索树的每个左子节点的值小于其父节点的值,每个右子节点的值大于其左子节点的值.如下图: 二叉搜索 ...
- 二叉搜索树的两种实现(数组模拟,STL)
书上实现: 二叉搜索数的特点:高效实现 插入一个数值,查询是否包含某个数值,删除某一个数值. 所有的节点都满足左子树上的所有节点都比自己的小,而右子树上的所有节点都比自己大的特点. 查询:如果当前数值 ...
- CF 675D——Tree Construction——————【二叉搜索树、STL】
D. Tree Construction time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法
二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...
- 二叉搜索树、AVL平衡二叉搜索树、红黑树、多路查找树
1.二叉搜索树 1.1定义 是一棵二叉树,每个节点一定大于等于其左子树中每一个节点,小于等于其右子树每一个节点 1.2插入节点 从根节点开始向下找到合适的位置插入成为叶子结点即可:在向下遍历时,如果要 ...
- [LeetCode] Serialize and Deserialize BST 二叉搜索树的序列化和去序列化
Serialization is the process of converting a data structure or object into a sequence of bits so tha ...
- [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 ...
- [LeetCode] Unique Binary Search Trees 独一无二的二叉搜索树
Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For examp ...
- PAT树_层序遍历叶节点、中序建树后序输出、AVL树的根、二叉树路径存在性判定、奇妙的完全二叉搜索树、最小堆路径、文件路由
03-树1. List Leaves (25) Given a tree, you are supposed to list all the leaves in the order of top do ...
随机推荐
- qt5.8+vs2015使用Qt5WebEngine搭建环境
转载请注明出处:http://www.cnblogs.com/dachen408/p/7575094.html 1.项目属性,C/C++,所有选项,附加包含目录新增. $(QTDIR)\include ...
- 基于jmeter和shell的接口性能自动化
基于jmeter和shell的接口性能自动化 1. 总体需求 由于性能测试中涉及的查询接口多,版本迭代频繁,版本更新后自动跑一轮查询业务的性能,可以及时发现一些开发修复bug触发的非预期的bug,利用 ...
- COGS 1361. 树
★ 输入文件:treed.in 输出文件:treed.out 简单对比时间限制:1 s 内存限制:128 MB [问题描述] 在一个凉爽的夏夜,xth和rabbit来到花园里砍树.为啥 ...
- 一个SAP开发人员的双截棍之路
由于种种原因,Jerry最近加入了SAP成都研究院的一个演讲俱乐部,这个俱乐部主要是提高大家的英语演讲能力. 说来Jerry也是大一下期和大二上期一次性高分通过四六级考试的,但是当毕业进入SAP成都研 ...
- (译)IOS block编程指南 2 block开始
Getting Started with Blocks(开始block) The following sections help you to get started with blocks usin ...
- type和isinstance区别
type只能对类型做直接的判断,主要用于获取未知变量的类型. 在程序中几乎很少用到type. 而isinstance功能比type更强,可以对子类型做出推理判断. isinstance主要用于判断A是 ...
- 暑假集训 || AC自动机
HDU 2222 题意:给n个模式串和一个字符串,求有多少个模式串在这个字符串中出现 思路:裸题,注意数组开的大小 #include <iostream> #include <cst ...
- 两个乒乓球队进行比赛,各出三人。 甲队为a,b,c三人,乙队为x,y,z三人。 已抽签决定比赛名单。 有人向队员打听比赛的名单。 a说他不和x比,c说他不和x,z比, 请编程序找出三队赛手的名单。
题目:两个乒乓球队进行比赛,各出三人. 甲队为a,b,c三人,乙队为x,y,z三人. 已抽签决定比赛名单. 有人向队员打听比赛的名单. a说他不和x比,c说他不和x,z比, 请编程序找出三队赛手的名单 ...
- 监控java进程是否正常运行
@echo off set _task=java.exe :checkstart for /f "tokens=1" %%n in ('tasklist ^| find " ...
- vue-cli中添加使用less
在vue-cli中构建的项目是可以使用less的,但是查看package.json可以发现,并没有less相关的插件,所以我们需要自行安装. 第一步:安装 npm install less less- ...