我正在尝试为快速操作创建一个基于链表的队列,现在这就是我所拥有的:
template< typename T,
template< typename > class Allocator = default_allocator
>
class fast_queue
{
public:
typedef T element_type;
typedef T* element_ptr;
private:
typedef struct e_node
{
element_type val;
e_node * next;
}node_type;
typedef node_type * node_ptr;
node_ptr parent;
node_ptr child;
int m_size;
typedef Allocator< node_type > allocator_type;
public:
fast_queue()
: parent( 0 )
, child( 0 )
, m_size( 0 )
{
}
~fast_queue() {
this->clear();
}
void push(element_type& i)
{
node_ptr n = allocator_type::alloc();
n->val = i;
n->next = (node_ptr)0;
if(child) {
child->next = n;
} else {
parent = n;
}
child = n;
m_size++;
}
element_type pop()
{
element_type ret = parent->val;
node_ptr p = parent;
parent = parent->next;
m_size--;
allocator_type::dealloc(p);
return ret;
}
inline int size() const
{
return m_size;
}
inline bool empty() const
{
return (m_size == 0);
}
void clear()
{
while(!empty()) {
pop();
}
child = 0;
}
};
非常简单,现在我遇到的问题是clear()函数。 似乎要花费太多时间来释放队列中的所有节点(7秒)。 所以问题是,什么可能是更好的算法?我试图了解MSVC对std :: deque的实现,但是代码是如此笨重让我理解。
编辑: 队列应该是通用的,允许任意类型的数据排队。 这是我的测试代码(Windows)
DWORD time1 = timeGetTime();
fast_queue<int> queue;
for(int i = 0; i < 100000; i++) {
queue.push(i);
}
queue.clear();
cout << "Test time: " << (int)(timeGetTime() - time1) << " milliseconds" << endl;
答案 0 :(得分:3)
您正在构建链接列表。 deque实现在每个分配中存储许多元素。但是,您可以为每个元素单独分配和释放。这就是你的队列太慢的原因。
除此之外,标准的队列接口表示您应该采用完整的分配器类型,而不是模板,尽管满足标准分配器要求的实际情况是它必须是模板。
答案 1 :(得分:1)
正如其他人所说,内存分配/解除分配是这里最大的性能问题。
我建议您尝试boost::circular_buffer。如果默认大小设置得足够高,则只会在其生命周期内分配一个内存。
答案 2 :(得分:1)
通过更改push / pop / clear算法,你无能为力,因为95%的时间用于节点的分配和释放。但是你可以做一些事情:
1)为节点使用某种内存池。您可以使用池分配器(如果您不想实现自己的,则boost :: pool_alloc是一个好的),或者您可以在队列类中使用内部节点缓存。因此,不是删除节点,而是将其推送到节点缓存,而在创建节点时,您可以从缓存中弹出它们。
2)在一个节点中存储多个项目。例如,如果一个节点中有8个项目,则每8次推送/弹出只需要分配/解除一次。当然,这需要稍微复杂的代码;除了指向头部和尾部节点的指针之外,您还需要两个索引变量来跟踪实际使用的项目数量。
答案 3 :(得分:1)
我不得不取出所有的Allocator东西来编译它(在g ++ 4.40下),但它立即运行。即使我推动了100多个元素,也只需要大约半秒钟来填充队列,半秒钟就可以清除它。您是否尝试过使用new并删除?