利用内存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
- 利用内存chunk充当数据buffer的泛型的双向队列的简单实现
- 利用内存chunk充当数据buffer的stack的一个简单实现
- 利用内存chunk充当数据buffer的vector的实现,和STL vector 有接口操作性能比较
- C实现的内存chunk管理器
- 利用defineProperty实现数据的双向绑定
- php简单的双向队列
- 实现Lua的双向队列
- Lua 双向队列的实现
- ArrayDeque利用数组建造的双向队列
- 完成端口(IOCP) 也可以这样用~~呵呵~ 用来充当线程之间的数据队列~
- 完成端口(IOCP) 也可以这样用~~呵呵~ 用来充当线程之间的数据队列~
- 用jquery实现的简单数据双向绑定
- 数据双向绑定的分析和简单实现
- 五十行javascript代码实现简单的双向数据绑定
- 五十行javascript代码实现简单的双向数据绑定
- 11、react之 实现数据的简单双向绑定
- 队列的双向链表实现
- 双向队列的链表实现
- CC_6_智力题
- HDU 1559 最大子矩阵
- A20-AT070TNA2配置
- [计算机基础]ARM-Linux系统调用
- 背包问题
- 利用内存chunk充当数据buffer的泛型的双向队列的简单实现
- IDEA无法启动:Failed to create JVM:error code -4
- mysql 启动错误时的处理方法
- 【Hibernate学习笔记】Hibernate的检索策略
- NSString 字符串
- Android开源项目第三篇——优秀项目篇
- tomcatpluginv33 下载
- JM参数详解
- 层次短语模型学习笔记