其他分享
首页 > 其他分享> > 无法在C中实现“绳索”数据结构

无法在C中实现“绳索”数据结构

作者:互联网

我正在尝试制作一个rope数据结构.它是一种二叉树,即递归数据结构.

绳索的目的是分裂和连接应该快,这意味着你避免复制整个绳索.
因此,例如,用户应该能够说出rope1 rope2并期望得到〜对数时间的结果.

但是,这提出了一个问题:
如果绳索被修改,其父母也会被间接修改.
因为我的目标是使绳子成为绳子的替代品,这是不可接受的.

我对此的解决方案是:每当绳索发生任何变化时,我都会创建一个新节点,稍微改变一下,保留旧节点不变.

从理论上讲,我认为这会很有效.

但实际上,它涉及(几乎?)每个字符串修改的堆分配.
即使是单字符更改也会导致新的堆对象,这不仅会自身缓慢,而且还会显着降低内存局部性,从而对性能产生负面影响.

我该如何解决这个问题?

解决方法:

传统的方法是copy-on-write:为此,您需要重新计算每个分配的节点.

如果修改后的节点的引用数为1(没有其他人引用它),则不需要复制它.

这个实际问题是有效地将变异与非变异操作分开:

    char& rope::operator[] (std::string::pos)

可能会改变引用的char,但是当它实际上不会强制选择const重载时,没有任何简单的方法.这意味着您要么必须假设发生突变,并且可能触发不必要的副本,或者返回一些重载char转换和赋值的代理.

这种方法是为std :: string的早期实现而尝试的(其中一个字符串相当于一个单节点的绳索)iirc,并且失宠了;部分是因为突变问题,部分是因为如果您不得不担心多线程,COW和所需的引用计数会变得越来越昂贵.

正如你所说,如果你的节点包含两种独立的状态类型,那么绳索还有一个问题:它自己的字符串和对它的子节点的引用(因为这会导致refcount / child引用突变传播树).

如果相反,字符仅存储在叶节点上,并且您执行非叶节点的完整副本(因此每条绳索都有自己的“目录结构”),您仍然可以避免复制字符,并且refcounted共享状态很多简单.

这会得到你想要的对数时间连接吗?也许不是:

>你必须复制所有非叶节点(并添加一个新的根),其数量是log的叶数
>你也必须增加叶子refcounts,这是线性的

它是否更接近线性或对数时间取决于递增引用计数与复制目录树的相对成本.

但是如果没有这个,你可以得到快速连接,但是如果必须在树上传播COW操作,任意字符访问可能(不可预测地)退化为对数时间.

我想,如果它适合你的用例,你可以实现移动连接:这可能会增加可能的恒定时间,你仍然可以避免额外的COW复杂性.

标签:c,data-structures,ropes
来源: https://codeday.me/bug/20190725/1537512.html