【问题标题】:Is it possible to efficiently reallocate data in front of itself?是否可以有效地重新分配自身前面的数据?
【发布时间】:2015-05-28 17:31:17
【问题描述】:

我制作了这个示例代码来说明我的问题:

/**
 * begin        end
 *   v           v
 * XXXXXXXXXXXXXXXX
 * ^
 * data
 *   [===========] size
 * [==============] capacity
 */
typedef struct list_t
{
    int *data;
    int *begin;
    int *end;
    size_t size;
    size_t capacity;
} list_t;


/**
 * begin        end
 *   v           v
 * XXXXXXXXXXXXXXXX
 * ^
 * old_data
 *
 * becomes
 *
 * begin        end
 *   v           v
 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 * ^
 * data
 */
void reserve_back(list_t *this) {
    int *old_data = this->data;

    this->capacity *= 2;
    this->data = (int *) realloc(this->data, this->capacity * sizeof(int));

    if (old_data != this->data) {
        this->begin = this->begin - old_data + this->data;
        this->end   = this->end - old_data + this->data;
    }
}

/**
 * begin        end
 *   v           v
 * XXXXXXXXXXXXXXXX
 * ^
 * old_data
 *
 * becomes
 *
 *                 begin        end
 *                   v           v
 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 * ^
 * data
 */
void reserve_front(list_t *this) {
    int *old_data = this->data;

    this->data = (int *) malloc(this->data, this->capacity * sizeof(int) * 2);
    memmove(this->data + this->capacity, old_data, this->capacity * sizeof(int));
    free(old_data);

    this->capacity *= 2;
    this->begin = this->begin - old_data + this->data;
    this->end   = this->end - old_data + this->data;
}

list_t 基本上是一个双端动态数组,在恒定时间内提供两端的 push 和 pop 操作,以及通常的随机访问。

当后面需要增加容量时,可以使用realloc重新分配数据块,realloc只在必要时才移动数据。 但是,为了增加前面的容量,我不得不每次都移动数据,这在大型列表中会变得非常繁重。

在已经分配的数据之前有可用内存的情况下,有没有办法在恒定时间内进行这种重新分配?

【问题讨论】:

    标签: c memory-management allocation realloc


    【解决方案1】:

    总之,没有。 (除非您编写自己的内存分配器,并且如果您尝试这样做,您很快就会明白为什么它没有在通用库分配器中实现。)

    一般来说,实现双端队列(deque)的最佳方式是将数据保存在段中,而不是尝试保存单个连续向量。只要段的大小合理,这几乎与索引访问或迭代的单个连续缓冲区一样快,而向任一端添加数据则更快。

    分段表示的一个缺点是您无法将双端队列的内容传递给需要简单向量的函数。另一方面,如果您不必经常这样做,您可能会因为观察到制作双端队列的扁平副本并不比复制向量以将其扩展到更大的内存分配更昂贵而感到放心.

    【讨论】:

    • 感谢您的回答,我想我会尝试使用分段来实现它并拥有一个可以更新的成员连续副本。什么是合理的段大小?它应该是相对于存储类型的大小,还是应该是一个常量?
    猜你喜欢
    • 2018-02-12
    • 2019-10-13
    • 1970-01-01
    • 1970-01-01
    • 2020-04-24
    • 2018-09-30
    • 1970-01-01
    • 2019-12-26
    • 1970-01-01
    相关资源
    最近更新 更多