C++固定大小的链表

C++ fixed-size linked list

本文关键字:链表 C++      更新时间:2023-10-16

不重复:

  • 哪个STL C++容器用于固定大小的列表?(具体用例(
  • std::列出固定大小(见下文(

动机:

分配发生一次(在构造函数中(,释放发生一次。

O(1(在列表中的任何位置插入和删除元素,而不需要处理内存管理的开销。这在基于数组的实现中是不可能的。

有没有一种直接的方法可以使用标准库来实现这一点?Boost中是否有类似的实现?

当我读到这篇文章时,我首先想到的是使用不同分配器的方法,即预先分配给定数量的元素以避免分配的代价。虽然我不熟悉定义分配器,但如果你发现了,我会对结果感兴趣。

如果没有这一点,这里有一个不同的方法。我为自己保存了template ...的东西,但我想如果你需要的话,你可以自己做。

typedef std::list<...> list_t;
struct fslist: private list_t
{
    // reuse some parts from the baseclass
    using list_t::iterator;
    using list_t::const_iterator;
    using list_t::begin;
    using list_t::end;
    using list_t::empty;
    using list_t::size;
    void reserve(size_t n)
    {
        size_t s = size();
        // TODO: Do what std::vector does when reserving less than the size.
        if(n < s)
            return;
        m_free_list.resize(n - s);
    }
    void push_back(element_type const& e)
    {
        reserve_one();
        m_free_list.front() = e;
        splice(end(), m_free_list, m_free_list.begin());
    }
    void erase(iterator it)
    {
        m_free_list.splice(m_free_list.begin(), *this, it);
    }
private:
    // make sure we have space for another element
    void reserve_one()
    {
        if(m_free_list.empty())
            throw std::bad_alloc();
    }
    list_t m_free_list;
};

这是不完整的,但它应该让你开始。还要注意,splice((并没有公开,因为将元素从不同的列表中移动或移动到不同的列表会改变大小和容量。

我认为最简单的方法是使用2个数据结构。固定大小的数组/向量,用于"分配"。您只需从数组中获取一个元素来创建一个节点,并将其插入到列表中。像这样的东西似乎符合您的要求:

struct node {
    node *prev;
    node *next;
    int value;
};
node storage[N];
node *storage_ptr = storage;

然后创建一个新节点:

if(node == &[storage + N]) {
    /* out of space */
}
node *new_node = *storage_ptr++;
// insert new_node into linked list

这是固定大小的,一次性分配,当storage超出范围时,节点将随之销毁。

至于有效地从列表中删除项目,这是可行的,但稍微复杂一些。我会有一个"已删除"节点的辅助链接列表。从主列表中删除node时,请将其插入"已删除"列表的末尾/开头。

分配时,在转到storage数组之前,请先检查已删除的列表。如果是NULL,请使用storage,否则,请将其从列表中删除。

我最终为此编写了一个名为rigid_list的模板。这还远未完成,但这是一个开始:

https://github.com/eltomito/rigid_list

(受Ulrich Eckhardt回答的启发(