利用内存chunk充当数据buffer的泛型的双向队列的简单实现

来源:互联网 发布:淘宝购物券网站 编辑:程序博客网 时间:2024/06/10 01:19

问题描述:


1.双向队列是程序设计中最常用到的数据结构,它是依据FIFO的操作抽象而出一种数据结构;

2.本文尝试自己封装一个泛型的double queue class,它支持常见的操作;

3.这个类的底层的数据存储容器是以双向链表串起来的内存块(memory chunk )实现,这样做主要是为了性能的考量

4.它支持两边插入和删除操作,其接口功能完全等同于STL 的deque;

5.最后我又封装一个底层容器为STL的deque class,这主要是为了性能比较的考虑;

6.最后我分别比较了以下四种情形的性能:

         1)AlDeque class (data container = memory chunk)
         2)  adapter deque class (data container = list )

         3)  adapter deque class (data container = deque)

 7. 性能测试结构发现:

         1)相互之间的时间之比基本上10倍关系;
          2)1消耗时间等于3的十分之一,3消耗时间等于2的十分之一;
          3)看过STL源代码的朋友应该知道,deque的内部实现用了相对复杂的数据结构(管理内存,以保证性能和操作),但是性能也不乐观;
          4)我的测试用例比较简单,感兴趣的朋友可下载源代码扩展测试;


程序代码:


#ifndef ALDEQUE_H_#define ALDEQUE_H_#include <deque>#include <vector>#include <list>#include "windows.h"/** a simple double direction queue. it's under container is memory chunk which can be list pointer* advantage: 1. good performance compare to stl queue*            2. simple implementation*/template<class T>class AlDeque{public:AlDeque():m_backBuffer(0),       m_frontBuffer(0), m_backElemCount(0),  m_frontElemCount(0), m_totalCount(0) {}~AlDeque(){Clear();}bool IsEmpty(){return m_totalCount == 0;}/** release all memory**/void Clear(){Buffer* cur = m_frontBuffer;while( cur != m_backBuffer ){m_frontBuffer = m_frontBuffer->next;delete cur;cur = 0;cur = m_frontBuffer;}delete m_backBuffer;}/** retrieve the number of elements inside queue**/size_t Size(){return m_totalCount;}/** push element to queue from back**/void PushBack( const T& data ){*PushBack() = data;}/** push element to queue from front**/void PushFront( const T& data ){*PushFront() = data;}/** pop element to queue from back**/void PopBack(){if( 0 == m_backBuffer )return;m_totalCount--;m_backElemCount--;if( 0 == m_backElemCount ){Buffer* cur = m_backBuffer;m_backBuffer = m_backBuffer->prev;delete cur;cur = 0;if( m_backBuffer ){m_backElemCount = KSlotCount;}else {m_frontBuffer = 0;return;}}}/** pop element to queue from front**/void PopFront(){if( 0 == m_frontBuffer )return;m_totalCount--;m_frontElemCount--;if( 0 == m_frontElemCount ){Buffer* cur = m_frontBuffer;m_frontBuffer = m_frontBuffer->next;delete cur;cur = 0;if( m_frontBuffer ){m_frontElemCount = KSlotCount;}else{m_backBuffer = 0;return;}}}/** retrieve element to queue from front**/T& Front(){assert( m_frontBuffer && m_frontElemCount );return m_frontBuffer->buf[KSlotCount - m_frontElemCount];}/** retrieve element to queue from back**/T& Back(){assert( m_backBuffer && m_backElemCount );return m_backBuffer->buf[ m_backElemCount - 1 ];}protected://disallow copy constructor and assignment operatorAlDeque( const AlDeque& rhs ){}AlDeque& operator = ( const AlDeque& rhs ){}// implementation of push from front T* PushFront(){m_totalCount++;if( 0 == m_frontBuffer ){m_frontBuffer = new Buffer;assert( m_frontBuffer );if( 0 == m_backBuffer ){m_backBuffer = m_frontBuffer;m_backElemCount = KSlotCount; //mark invalid for back insert}m_frontElemCount = 0;}else{if(  KSlotCount == m_frontElemCount )  //full currently buffer{Buffer* newBuf = new Buffer;assert( newBuf );newBuf->next = m_frontBuffer;m_frontBuffer->prev = newBuf;m_frontBuffer = newBuf;m_frontElemCount = 0;}}return &m_frontBuffer->buf[ KSlotCount - (++m_frontElemCount)];}// implementation of push from back T* PushBack(){m_totalCount++;if( 0 == m_backBuffer ){m_backBuffer = new Buffer;if( 0 == m_frontBuffer ){m_frontBuffer = m_backBuffer;m_frontElemCount = KSlotCount; //mark invalid for front insert}m_backElemCount = 0;}else{if( KSlotCount == m_backElemCount )  //full currently buffer{Buffer* newBuf = new Buffer;assert( newBuf );newBuf->prev = m_backBuffer;m_backBuffer->next = newBuf;m_backBuffer = newBuf;m_backElemCount = 0;}}return &m_backBuffer->buf[m_backElemCount++];}protected:enum {KSlotCount = 64};struct Buffer{T        buf[KSlotCount];Buffer*  next;Buffer*  prev;Buffer():next(0), prev(0){memset( buf, 0x00, sizeof(buf) );}};Buffer*    m_backBuffer; // data buffer corresponding to back operationBuffer*    m_frontBuffer; // data buffer corresponding to front operationsize_t     m_backElemCount; // size_t     m_frontElemCount;size_t     m_totalCount;  // total elements};/** adapter class **/template<class T, class Container = std::list<T> >class DequeAdaptStl{public:DequeAdaptStl():m_dataContainer(){}~DequeAdaptStl(){m_dataContainer.clear();}void Clear(){m_dataContainer.clear();}size_t Size(){return m_dataContainer.size();}void PushBack( const T& data ){m_dataContainer.push_back( data );}void PushFront( const T& data ){m_dataContainer.push_front( data );}void PopBack(){m_dataContainer.pop_back();}void PopFront(){m_dataContainer.pop_front();}T& Front(){return m_dataContainer.front();}T& Back(){return m_dataContainer.back();}protected:Container  m_dataContainer;};/** unit test **/template<class container>void UnitTestDeque( container& queObj, const char* str ){const int len = 64 * 10000;unsigned long start = GetTickCount();//unit test 1 // insert and pop in corresponding direction{for( int i = 0; i < len; i++ ){queObj.PushBack( i );}for( int i = 0; i < len; i++ ){int sel = queObj.Back();assert( sel == len - 1 - i );queObj.PopBack();}for( int i = 0; i < len; i++ ){queObj.PushFront( i );}for( int i = 0; i < len; i++ ){int sel = queObj.Front();assert( sel == len - i  - 1);queObj.PopFront();}}//unit test 2// insert and pop in reverse direction{for( int i = 0; i < len; i++ ){queObj.PushBack( i );}for( int i = 0; i < len; i++ ){int sel = queObj.Front();assert( sel == i );queObj.PopFront();}for( int i = 0; i < len; i++ ){queObj.PushFront( i );}for( int i = 0; i < len; i++ ){int sel = queObj.Back();assert( sel == i );queObj.PopBack();}}//unit test 2// test release interface{for( int i = 0; i < len; i++ ){queObj.PushBack( i );}for( int i = 0; i < len; i++ ){queObj.PushFront( i );}queObj.Clear();}unsigned long interval = GetTickCount() - start;printf( "%s consume time is %d \n", str, interval );}/** Test interface **/void TestAlDeque(){AlDeque<int> alDeque;UnitTestDeque( alDeque, "the deqeue of memory chunk" );DequeAdaptStl<int> dequeList;UnitTestDeque( dequeList, "the deqeue of container list" );DequeAdaptStl<int, std::deque<int> > dequeSTL;UnitTestDeque( dequeSTL, "the deqeue really" );getchar();}#endif 

compile and run in visual studio 2005
test result as follows:



1 0
原创粉丝点击