首页 > 其他 > 详细

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

时间:2014-04-26 21:41:37      阅读:637      评论:0      收藏:0      [点我收藏+]

问题描述:


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 operator
	AlDeque( 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 operation

	Buffer*    m_frontBuffer; // data buffer corresponding to front operation

	size_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:
bubuko.com,布布扣


利用内存chunk充当数据buffer的泛型的双向队列的简单实现,布布扣,bubuko.com

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

原文:http://blog.csdn.net/manthink2005/article/details/24534501

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!