5.1 树
1、二叉搜索树
任何节点的键值一定大于其左子树的每一个节点的键值,并小于其右子树的每一个节点的键值。
插入:插入新元素时,从根节点开始,遇键值较大就向左,遇到键值较小者就向右,一直到尾端,即为插入点。
删除:分两种情况。如果A只有一个子节点,就直接将A的子节点连至A的父节点,并将A删除。如果A有两个子节点,就以右子树内的最小节点取代A(右子树的最小节点为:从右子节点开始,一直向左走到底即是)。
2、平衡二叉搜索树有AVL-tree、RB-tree、AA-tree等。
3、AVL tree
要求任何节点的左右子树高度相差最多1。
(1)插入:分四种情况,为两类。
对于外侧插入,采用单旋转:
对于内侧插入,采用双旋转:
5.2 RB-tree(红黑树)
每个节点不是红色就是黑色;根节点是黑色;如果节点是红色,其子节点必须是黑色;任一节点至NULL(树尾端)的任何路径,所含黑节点树必须相同。
根据规则4,新增节点必须为红;根据规则3,新增节点之父节点必须为黑。
1、插入节点(根据插入位置和外围节点颜色分类)
状况1:S(伯父节点)为黑且为外侧插入。单旋转并改变P(父亲)、G(祖父)颜色。
状况2:S为黑且X为内侧插入。先对P、X做一次单旋转并更改G、X颜色,在对G做一次单旋转。
状况3:S为红。先将P、S变为黑,G变为红(注意G的父亲GG也是红,需要向上不断进行),转化为状况1或2。
2、RB-tree的节点设计
typedef bool __rb_tree_color_type;
const __rb_tree_color_type __rb_tree_red = false;
const __rb_tree_color_type __rb_tree_black = true;
struct __rb_tree_node_base
{
typedef __rb_tree_color_type color_type;
typedef __rb_tree_node_base* base_ptr;
color_type color;
base_ptr parent;
base_ptr left;
base_ptr right;
}
template <class Value>
struct __rb_tree_node : public __rb_tree_node_base
{
typedef __rb_tree_node<Value>* link_type;
Value value_field;
}
4、RB-tree的迭代器
void increment()
{
if (node->right != 0) {
node = node -> right;
while (node->right != 0) {
node = node -> left;
}
} else {
base_ptr y = node -> parent;
while (node == y->right) { //可以看到没有判断y是否为NULL,这是因为class rb_tree中link_type header的存在。parent一定存在。
node = y;
y = y->parent;
}
if (node->right != y) //可以考虑RB树中只有一个根节点和header节点的情况。
node = y; //注意end()即为header。
}
}
5、RB-tree的数据结构
template <class Key, class Value, class KeyOfValue, class Compare,
class Alloc = alloc> //KeyOfValue和Compare应当是一个仿函数
class rb_tree {
protected:
typedef void* void_pointer;
typedef __rb_tree_node_base* base_ptr;
typedef __rb_tree_node<Value> rb_tree_node;
typedef simple_alloc<rb_tree_node, Alloc> rb_tree_node_allocator;
typedef __rb_tree_color_type color_type;
public:
typedef Key key_type;
typedef Value value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef rb_tree_node* link_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
protected:
link_type get_node() { return rb_tree_node_allocator::allocate(); }
void put_node(link_type p) { rb_tree_node_allocator::deallocate(p); }
link_type create_node(const value_type& x) {
link_type tmp = get_node();
__STL_TRY {
construct(&tmp->value_field, x);
}
__STL_UNWIND(put_node(tmp));
return tmp;
}
link_type clone_node(link_type x) {
link_type tmp = create_node(x->value_field);
tmp->color = x->color;
tmp->left = 0;
tmp->right = 0;
return tmp;
}
void destroy_node(link_type p) {
destroy(&p->value_field);
put_node(p);
}
protected:
size_type node_count; // keeps track of size of tree
link_type header;
Compare key_compare;
link_type& root() const { return (link_type&) header->parent; }
link_type& leftmost() const { return (link_type&) header->left; }
link_type& rightmost() const { return (link_type&) header->right; } //返回值是一个指针的引用,这样可以使我们能直接修改这个指针的值,而header->right本身可能为NULL。
...
};
关于header:其实就是根节点的父节点,以简化边界情况处理。( header和root互为对方的父节点!)
void init() {
header = get_node();
color(header) = __rb_tree_red; // used to distinguish header from
// root, in iterator.operator++
root() = 0;
leftmost() = header;
rightmost() = header;
}
iterator begin() { return leftmost(); } //RB树的起头为最左(最小)节点处
iterator end() { return header; } //RB树的终点为header所指处
6、RB-tree的构造与内存管理
7、RB-tree的元素操作
(1)元素的插入
insert_unique():被插入节点的键值在整棵树中必须独一无二;
insert_equal():键值可以重复。
(2)元素的搜索