昨天写完了音频的回放程序,在写音频捕捉程序时,突然有了一个想法,急于想知道它和Deque来比,哪一个速度更快,于是暂停了音频捕捉程序,写了一个DequeEx,经测试,它在进行前插入、后插入、前读取、后读取、随机访问时的时间均为常数n,比Deque的速度快了5倍。但它在进行中间插入和删除时的速度肯定要慢于Deque,因此我没有增加中间插入和删除的方法。有兴趣的朋友可以测试一下。
其程序代码如下:其中MSGDEQUE定义如下,因为这个已经在DLL中定义了,因此,在测试时,请自己将下面三行代码添加在DequeEx.h文件中:
#include <deque> using namespace std; typedef deque<DWORD> MSGDEQUE;
DequeEx.h文件如下: // DequeEx.h: interface for the DequeEx class. // //////////////////////////////////////////////////////////////////////
#if !defined(AFX_DEQUEEX_H__57392FC5_5F59_4B58_B506_2D7B6FB7331C__INCLUDED_) #define AFX_DEQUEEX_H__57392FC5_5F59_4B58_B506_2D7B6FB7331C__INCLUDED_
#if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000
enum { //设定主要操作的模式。 PUSH_BACK, //主要操作为从后插入。 PUSH_FRONT, //主要操作为从前插入。 PUSH_MIDDLE, //主要操作为从中间插入。 };
//DequeEx是对Dqueue的扩展,它在进行前插、后插、前读取、后读取、随机访问时的速度均为常数n。 //在进行上述操作时的速度,比Dqueue快5倍。
class AFX_EXT_CLASS DequeEx : public CObject { public: void clear(); //清空列表,并释放缓存。 int size(); //得到当前列表中的元素的个数。 bool empty(); //列表是否为空。 DWORD pop_back(); //从列表的尾弹出一个元素。 DWORD pop_front(); //从列表的头弹出一个元素。 void push_front(DWORD value); //将元素放入列表的最前面。 void push_back(DWORD value); //将元素放入列表的最后面。 void SetElementsNoPerBufferAdd(WORD wElementsNoPerAdd); //设置每次缓冲区增加时所增加的元素个数。 void SetFrequentlyAddElementMode(int nMode,WORD wOffset=0); //设置列表频繁进行操作时的方式。 DWORD operator [](int nIndex); //以索引方式直接访问列表中的元素。 //列表在初始化,缺省认为是在列表的两头都进行插入和删除操作。 //如果只想在列表的一边进行插入操作,应该调用SetFrequentlyAddElementMode()方法, //设定相应的模式,将提高插入元素时的速度。 //如果列表有可能进行保存很多的元素,则应该调用SetElementsNoPerBufferAdd()方法, //增大每次缓冲区增加的大小,可以明显提高速度。 DequeEx(WORD wElementsNoPerAdd=20, int nMode=PUSH_MIDDLE, WORD wOffset=10); ~DequeEx();
private: void InitData(); void CheckBuffer(); char* m_pBuffHead; //缓冲区的头指针。 DWORD m_dwBuffSize; //缓冲区的尺寸。 char* m_pBuffTail; //缓冲区的尾指针。 char* m_pHead; //有效数据的始点。 char* m_pTail; //有效数据的尾指针。
WORD m_wElementsNoPerAdd; //每次增加的元素个数。 DWORD m_dwBuffSizePerAdd/*=m_wElementsNoPerAdd*4*/; //每次增加的缓冲区的大小。 DWORD m_dwOffset; //每次改变缓冲区大小时,在m_szEnter前预留的字节个数。 };
#endif // !defined(AFX_DEQUEEX_H__57392FC5_5F59_4B58_B506_2D7B6FB7331C__INCLUDED_)
DequeEx.cpp文件如下: // DequeEx.cpp: implementation of the DequeEx class. // //////////////////////////////////////////////////////////////////////
#include "stdafx.h" #include "DequeEx.h"
#ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif
////////////////////////////////////////////////////////////////////// // Construction/Destruction //////////////////////////////////////////////////////////////////////
DequeEx::DequeEx(WORD wElementsNoPerAdd/*=20*/, int nMode/*=PUSH_MIDDLE*/, WORD wOffset/*=10*/) { this->InitData(); this->SetElementsNoPerBufferAdd(wElementsNoPerAdd); this->SetFrequentlyAddElementMode(nMode,wOffset); }
DequeEx::~DequeEx() {
}
void DequeEx::SetElementsNoPerBufferAdd(WORD wElementsNoPerAdd) { this->m_wElementsNoPerAdd=wElementsNoPerAdd; this->m_dwBuffSizePerAdd=this->m_wElementsNoPerAdd*4; }
void DequeEx::SetFrequentlyAddElementMode(int nMode,WORD wOffset/*=0*/) { switch(nMode) { //根据操作模式,设定偏移。 case PUSH_BACK: this->m_dwOffset=0; break; case PUSH_FRONT: this->m_dwOffset=this->m_wElementsNoPerAdd*4; break; default: //缺省时为PUSH_MIDDLE: if(wOffset>this->m_wElementsNoPerAdd || wOffset==0) wOffset=this->m_wElementsNoPerAdd/2; this->m_dwOffset=wOffset*4; break; } }
void DequeEx::CheckBuffer() { if(this->m_pHead==NULL) { //如果缓冲区为空。 this->m_pBuffHead=new char[this->m_dwBuffSizePerAdd]; this->m_pBuffTail=this->m_pBuffHead+this->m_dwBuffSizePerAdd; this->m_pHead=this->m_pBuffHead+this->m_dwOffset; this->m_pTail=this->m_pHead; this->m_dwBuffSize=this->m_dwBuffSizePerAdd; } else { //如果数据区已经到了缓冲区的尾。 DWORD dwLen=this->m_pTail-this->m_pHead; //数据的实际长度。 if(dwLen==0) { //如果数据区的长度为。 this->m_pHead=this->m_pBuffHead+this->m_dwOffset; this->m_pTail=this->m_pHead; } else if((dwLen+this->m_dwOffset)>=this->m_dwBuffSize) { //如果数据区的头与缓冲区头之间的尺寸小于等于设定的偏移尺寸,则增加缓冲。 this->m_dwBuffSize+=this->m_dwBuffSizePerAdd; char* sz=new char[this->m_dwBuffSize]; memcpy(sz+this->m_dwOffset,this->m_pHead,dwLen); delete []this->m_pBuffHead; this->m_pBuffHead=sz; this->m_pBuffTail=sz+this->m_dwBuffSize; this->m_pHead=sz+this->m_dwOffset; this->m_pTail=this->m_pHead+dwLen; } else { //如果数据区的头与缓冲区头之间的尺寸大于设定的偏移尺寸,则将数据移动到距缓冲区头的偏移尺寸处。 memcpy(this->m_pBuffHead+this->m_dwOffset,this->m_pHead,dwLen); this->m_pHead=this->m_pBuffHead+this->m_dwOffset; this->m_pTail=this->m_pHead+dwLen; } } }
void DequeEx::push_back(DWORD value) { if((this->m_pTail+4)>this->m_pBuffTail) this->CheckBuffer(); this->m_pTail[0]=(BYTE)value; this->m_pTail[1]=(BYTE)(value>>8); this->m_pTail[2]=(BYTE)(value>>16); this->m_pTail[3]=(BYTE)(value>>24); this->m_pTail+=4; }
void DequeEx::push_front(DWORD value) { char* psz=this->m_pHead-4; if(psz<this->m_pBuffHead || psz>this->m_pBuffTail) { this->CheckBuffer(); psz=this->m_pHead-4; } psz[0]=(BYTE)value; psz[1]=(BYTE)(value>>8); psz[2]=(BYTE)(value>>16); psz[3]=(BYTE)(value>>24); this->m_pHead-=4; }
DWORD DequeEx::pop_front() { if(this->m_pHead>=this->m_pTail) return 0; DWORD dw=MAKELONG(MAKEWORD(this->m_pHead[0],this->m_pHead[1]), MAKEWORD(this->m_pHead[2],this->m_pHead[3])); this->m_pHead+=4; return dw; }
DWORD DequeEx::pop_back() { if(this->m_pTail<=this->m_pHead) return 0; this->m_pTail-=4; DWORD dw=MAKELONG(MAKEWORD(this->m_pTail[0],this->m_pTail[1]), MAKEWORD(this->m_pTail[2],this->m_pTail[3])); return dw; }
bool DequeEx::empty() { return this->m_pTail==this->m_pHead; }
int DequeEx::size() { return (this->m_pTail-this->m_pHead)/4; }
DWORD DequeEx::operator [](int nIndex) { char* psz=this->m_pHead+nIndex*4; if(psz<this->m_pTail) return MAKELONG(MAKEWORD(psz[0],psz[1]),MAKEWORD(psz[2],psz[3])); return 0; }
void DequeEx::clear() { delete []this->m_pBuffHead; this->InitData(); }
void DequeEx::InitData() { this->m_pBuffHead=NULL; this->m_pBuffTail=NULL; this->m_pHead=NULL; this->m_pTail=NULL; this->m_dwBuffSize=0; } 测试程序如下:
{ if(true) { //DequeEx测试随机访问。 DequeEx queue; DWORD dw=23456789; WORD w=65000; // WORD ws=10000; // queue.SetElementsNoPerBufferAdd(ws); queue.SetFrequentlyAddElementMode(PUSH_MIDDLE,10); SYSTEMTIME time,time2; ::GetSystemTime(&time); for(int i=0;i<100;i++) queue.push_front(dw); for(int j=0;j<w;j++) { for(i=0;i<100;i++) dw=queue[i]; } ::GetSystemTime(&time2); int sec=time2.wSecond-time.wSecond; if(sec<0) { sec=time2.wSecond+60-time.wSecond; } int msec=time2.wMilliseconds-time.wMilliseconds; if(msec<0) { sec--; msec=time2.wMilliseconds+1000-time.wMilliseconds; } DWORD t=sec*1000+msec;
//Deque后插入数据,前读取数据测试。 MSGDEQUE md; ::GetSystemTime(&time); for(i=0;i<100;i++) md.push_front(dw); for(j=0;j<w;j++) { for(i=0;i<100;i++) dw=md[i]; } ::GetSystemTime(&time2); sec=time2.wSecond-time.wSecond; if(sec<0) { sec=time2.wSecond+60-time.wSecond; } msec=time2.wMilliseconds-time.wMilliseconds; if(msec<0) { sec--; msec=time2.wMilliseconds+1000-time.wMilliseconds; } t=sec*1000+msec; msec=t; }
if(!true) { //DequeEx前插入数据,后读数据测试。 DequeEx queue; DWORD dw=23456789; WORD w=65000; // WORD ws=10; // queue.SetElementsNoPerBufferAdd(ws); queue.SetFrequentlyAddElementMode(PUSH_MIDDLE,10); SYSTEMTIME time,time2; ::GetSystemTime(&time); for(int j=0;j<w;j++) { for(int i=0;i<78;i++) queue.push_front(dw); queue.push_front(12345678); queue.push_front(456); for(i=0;i<30;i++) dw=queue.pop_back(); for(i=0;i<20;i++) queue.push_front(dw); for(i=0;i<70;i++) dw=queue.pop_back(); } ::GetSystemTime(&time2); int sec=time2.wSecond-time.wSecond; if(sec<0) { sec=time2.wSecond+60-time.wSecond; } int msec=time2.wMilliseconds-time.wMilliseconds; if(msec<0) { sec--; msec=time2.wMilliseconds+1000-time.wMilliseconds; } DWORD t=sec*1000+msec;
//Deque后插入数据,前读取数据测试。 MSGDEQUE md; ::GetSystemTime(&time); for(j=0;j<w;j++) { for(int i=0;i<80;i++) md.push_front(dw); dw=md[0]; for(i=0;i<30;i++) md.pop_back(); for(i=0;i<20;i++) md.push_front(dw); for(i=0;i<70;i++) md.pop_back(); } ::GetSystemTime(&time2); sec=time2.wSecond-time.wSecond; if(sec<0) { sec=time2.wSecond+60-time.wSecond; } msec=time2.wMilliseconds-time.wMilliseconds; if(msec<0) { sec--; msec=time2.wMilliseconds+1000-time.wMilliseconds; } t=sec*1000+msec; msec=t; }
if(!true) { //DequeEx后插入数据,前读数据测试。 DequeEx queue; DWORD dw=23456789; WORD w=65000; WORD ws=10; queue.SetElementsNoPerBufferAdd(ws); SYSTEMTIME time,time2; ::GetSystemTime(&time); for(int j=0;j<w;j++) { for(int i=0;i<80;i++) queue.push_back(dw); for(i=0;i<30;i++) dw=queue.pop_front(); for(i=0;i<20;i++) queue.push_back(dw); for(i=0;i<70;i++) dw=queue.pop_front(); } ::GetSystemTime(&time2); int sec=time2.wSecond-time.wSecond; if(sec<0) { sec=time2.wSecond+60-time.wSecond; } int msec=time2.wMilliseconds-time.wMilliseconds; if(msec<0) { sec--; msec=time2.wMilliseconds+1000-time.wMilliseconds; } DWORD t=sec*1000+msec;
//Deque后插入数据,前读取数据测试。 MSGDEQUE md; ::GetSystemTime(&time); for(j=0;j<w;j++) { for(int i=0;i<80;i++) md.push_back(dw); for(i=0;i<30;i++) md.pop_front(); for(i=0;i<20;i++) md.push_back(dw); for(i=0;i<70;i++) md.pop_front(); } ::GetSystemTime(&time2); sec=time2.wSecond-time.wSecond; if(sec<0) { sec=time2.wSecond+60-time.wSecond; } msec=time2.wMilliseconds-time.wMilliseconds; if(msec<0) { sec--; msec=time2.wMilliseconds+1000-time.wMilliseconds; } t=sec*1000+msec; msec=t; } }

|