在不浪费内存的情况下增强数据结构
Augmenting data structure without wasting memory
我有一个类Tree
,我想将其扩充为更专业的数据结构,例如Order_tree
和Interval_tree
。这些增强需要对Node
进行添加,例如大小信息,以及对某些算法的微小更改。
我想知道在性能、可读性和可维护性方面实现C++增强的最佳方法。不应以多态方式使用树。到目前为止,我尝试的是公开继承Tree
,然后重载基本方法。(我很抱歉我是面向对象编程的初学者(
template <typename T>
class Tree {
protected:
enum class Color : char {BLACK = 0, RED = 1};
struct Node {
T key;
Node *parent, *left, *right;
Color color;
Node() : color{Color::BLACK} {} // sentinel construction
Node(T val, Color col = Color::RED) : key{val}, parent{nil}, left{nil}, right{nil}, color{col} {}
};
using NP = typename Tree::Node*;
NP root {nil};
// nil sentinel
static NP nil;
// core utility algorithms...
};
template <typename T>
typename Tree<T>::NP Tree<T>::nil {new Node{}};
订单树
template <typename T>
class Order_tree : public Tree<T> {
using Color = typename Tree<T>::Color;
using Tree<T>::Tree; // inherit constructors
struct Order_node {
T key;
Order_node *parent, *left, *right;
size_t size; // # of descendent nodes including itself = left->size + right->size + 1
Color color;
Order_node() : size{0}, color{Color::BLACK} {} // sentinel construction
Order_node(T val, Color col = Color::RED) : key{val}, parent{nil}, left{nil}, right{nil}, size{1}, color{col} {}
};
using NP = typename Order_tree::Order_node*;
NP root {nil};
static NP nil;
// overloading on only the methods that need changing
};
template <typename T>
typename Order_tree<T>::NP Order_tree<T>::nil {new Order_node{}};
但是,这不能正常工作,因为现在我有 2 个根和 2 个 nil,所有基本方法都在基根上工作,并且使用 Tree<T>::NP
而不是 Order_tree::NP
因此无法使用Order_node
的大小属性。
一种方法是复制粘贴代码,这是非常不可维护的。我认为另一种方法是在 T 和 NP 上模板树,以便Order_tree
是别名using Order_tree = Tree<Order_node>
并在节点上专门化树。
如果您真的对拥有"所有树的一般树"感兴趣,那么问题似乎不在于树,而在于 Node。你需要一些节点的特殊情况,那么为什么不也泛化它们呢?例如:
template <typename T>
class Tree {
protected:
struct BaseNode {
//all code you really can generalize here
};
struct Node : public BaseNode {
//You need Node here only if you want your base Tree class to be ready to use.
//If you want to use only its derives such as Order_tree,
//you create special nodes kinds only there
};
// core utility algorithms...
BaseNode * root; //Only one root node, there is no need in duplication!
//You can instantiate it as root = new OrderTreeNode or root = new SpecialTreeNode in any derives.
};
然而,Node虚函数调用的价格相当高。所以你需要清楚地理解 - 你需要泛化而不是代码重复,还是你需要性能。
经过一些实验,我找到了实现我想要的东西的最佳方法:
- 节点类型的模板树
- 使 nil 成为每个节点类型的静态元素
- 移动一些在节点上工作的私有方法,而不依赖于根目录为节点上的正常函数模板化
- 使可能更改的功能成为虚拟功能
- 公开增加树从中继承并覆盖必要的虚函数
- 使用基树的根(在派生类中不保存任何数据(
现在是什么样子的:
树.h
namespace sal {
// utilities with no dependence on root, outside of class now
template <typename Node>
Node* tree_find(Node* start, typename Node::key_type key) {
while (start != Node::nil && start->key != key) {
if (key < start->key) start = start->left;
else start = start->right;
}
return start;
}
// more of them...
template <typename Node>
class Tree {
protected:
using NP = Node*;
using T = typename Node::key_type;
// nil is static member of each Node type now
NP root {Node::nil};
// virtual methods that could be changed by augmentation
virtual void rotate_left(NP node);
virtual void rotate_right(NP node);
virtual void tree_insert(NP start, NP node);
virtual void rb_delete(NP node);
// non-virtual methods that are never overridden
void rb_insert_fixup(NP node);
void rb_delete_fixup(NP successor);
void rb_insert(NP node); // just a call to tree_insert and rb_insert_fixup
void transplant(NP old, NP moved);
public:
virtual ~Tree(); // does all the clean up so its derived classes don't have to
// interface...
};
template <typename T>
struct Basic_node {
static Basic_node* nil;
using key_type = T;
T key;
Basic_node *parent, *left, *right;
Color color;
Basic_node() : color{Color::BLACK} {} // sentinel construction
Basic_node(T val) : key{val}, parent{nil}, left{nil}, right{nil}, color{Color::RED} {}
};
template <typename T>
using Basic_tree = Tree<Basic_node<T>>;
template <typename T>
Basic_node<T>* Basic_node<T>::nil {new Basic_node{}};
}
order_tree.h
#include "tree.h"
namespace sal {
template <typename Node>
class Order_augment : public Tree<Node> {
using NP = Node*;
using T = typename Node::key_type;
using Tree<Node>::root;
// no need to redefine shared core functions
using Tree<Node>::rb_insert;
using Tree<Node>::transplant;
using Tree<Node>::rb_insert_fixup;
using Tree<Node>::rb_delete_fixup;
// order statistics operations
NP os_select(NP start, size_t rank) const;
size_t os_rank(NP node) const;
// modification of rb operations to maintain augmentation
virtual void tree_insert(NP start, NP node) override;
virtual void rb_delete(NP node) override;
virtual void rotate_left(NP node) override;
virtual void rotate_right(NP node) override;
public:
// augmented interface
};
template <typename T>
struct Order_node {
static Order_node* nil;
using key_type = T;
T key;
Order_node *parent, *left, *right;
size_t size; // # of descendent nodes including itself = left->size + right->size + 1
Color color;
Order_node() : size{0}, color{Color::BLACK} {} // sentinel construction
Order_node(T val) : key{val}, parent{nil}, left{nil}, right{nil}, size{1}, color{Color::RED} {}
};
template <typename T>
Order_node<T>* Order_node<T>::nil {new Order_node{}};
template <typename T>
using Order_tree = Order_augment<Order_node<T>>;
}
结果是,包含增强数据结构的文件大小现在大约是原来的 1/3,并且代码重复被完全删除!这意味着任何改进核心方法的更改都可以本地化为仅 tree.h,其效果也将在所有增强树中感受到。
相关文章:
- 在没有太多条件句的情况下,我如何避免被零除
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 在未初始化映射的情况下,将值插入到映射的映射中
- 是默认情况下分配给char数组常量的值
- 为什么我不能在不创建字符串变量的情况下使用函数的字符串输出
- 如何在不产生任何垃圾的情况下获得C中的像素
- 在已经使用Git的情况下减少编译时间
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 如何在没有信号的情况下从C++执行QML插槽
- 如何在不知道向量大小的情况下输入向量内部的向量?
- 为什么在某些情况下不写入此文件?
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 在没有Xcode的情况下在Mac捆绑包中嵌入框架
- UE4-如何在给定4个屏幕坐标的情况下缩放纹理或材质
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 在C++中如何在没有pow的情况下进行基础计算
- 松弛原子与无同步情况下的记忆连贯性
- 在不浪费内存的情况下增强数据结构
- 在不关闭连接的情况下,在循环中增强asio加密
- 在关闭RTTI的情况下增强简单类的序列化(-fno-rtti)