队列算法

时间:2011-01-15 13:29:57

标签: c++ algorithm performance queue

我正在尝试为快速操作创建一个基于链表的队列,现在这就是我所拥有的:

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;

4 个答案:

答案 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并删除?