Array,List,Map

本文详细对比了MFC中的Array、List和Map三种集合类的特性与应用场景,包括它们的内存结构、检索效率以及插入删除操作的性能,并提供了实用的应用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Collections类族主要包括三种形式及其不同应用:

 

    Array — CArray, CObArray, CStringArray, CPtrArray, CByteArray, CWordArray, CDWordArray, CTypedPtrArray

 

    List — CList, CObList, CStringList, CPtrList

 

    CMap — CMap, CTypedPtrMap, CMapPtrToPtr, CMapPtrToWord, CMapWordToPtr, CMapStringToPtr

 

整体比较:

 

属性 类族 特点

内存结构 Array VC源码CArray::SetSize()中可看到:

TYPE* pNewData = (TYPE*) new BYTE[nNewMax * sizeof(TYPE)];

// copy new data from old

memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));

// construct remaining elements

ASSERT(nNewSize > m_nSize);

ConstructElements<TYPE>(&pNewData[m_nSize], nNewSize-m_nSize);

// get rid of old stuff (note: no destructors called)

delete[] (BYTE*)m_pData;

m_pData = pNewData;

而在RemoveAt()中则有:

int nMoveCount = m_nSize - (nIndex + nCount);

DestructElements<TYPE>(&m_pData[nIndex], nCount);

if (nMoveCount)

memmove(&m_pData[nIndex], &m_pData[nIndex + nCount],

nMoveCount * sizeof(TYPE));

m_nSize -= nCount;

 

可见Array采用队列方式存储数据,因而其内部数据元素是以物理方式顺序排列的,所以检索、顺序执行GetAt()等函数的速度是相当快的。但是由于每次队列长度变化后,数据都要重新申请内存、拷贝内存、释放内存,因而Insert/Add/RemoveAt()的速度都很慢。

 

如果你使用的数据元素尺寸相当大,而且数组的操作相当复杂,频繁(1E4以上的)使用InsertAt/SetAt/RemoveAt等,应该考虑使用CList来代替。

 

一个特例是PtrArray/CTypedPtrArray,其内部数据是某个数据地址,而非数据本身,所以其效率更接近CList

 

List VC源码CList::AddTail()中可看到:

CNode* pNewNode = NewNode(m_pNodeTail, NULL);

pNewNode->data = newElement;

    if (m_pNodeTail != NULL)

m_pNodeTail->pNext = pNewNode;

因而List采用链表方式存储数据,因而当链表数据有所变动时,只做了一下指向变动,所以即使数据元素非常多单个数据元素也很大,执行Insert/Add/Remove的速度都很快,但是因为没有统一的Index,因而如果要找到某个元素只有遍历整个链表。

 

整体上说,List的使用比较繁琐,特别为小尺寸数据设计List更是得不偿失的,这也是为什么有CWordArray而没有CWordList的原因,因而在大多数情况下应该有限考虑是否可以使用Array来存储数据。

 

Map Map采用杂凑(Hashing)表方式来存储和检索数据,其内容包括KeyValue的双列表及其之间的映射关系表。例如在OODBLib用到的::FhtRegister <Class>()函数,在内部使用了Key=Class名称/Value=Class与数据库列的映射,从而在使用Class时只需要知道类的名字即可找到与之对应的数据库映射方法。

在下面的Characteristics表中可看到,Key的数值不可重复,即只能是唯一的(例如在上例中同一个程序中不可能有两个相同名字的类的声明),而Value可重复(不同名字的类可有完全相同的变量和函数)

 

尽管杂凑表使用了高效的检索方式,大量使用CMap::LookUp()函数还是很耗时的,400 000LookUp()执行时间大约是1秒,而同样次数的CObArray::GetAt()函数只需要0.3秒。

 

应用技巧 Array ①如果在你所使用的场合中,出现下列情况之一:a.数据元素的尺寸很大b.经常需要执行Add函数(例如数据库在执行Select语句时) 则需要事先执行SetSize(int nSize,int nGrowBy)函数,事先确定大致尺寸(之后仍可增加)及每次增加时一次申请的内存数,从而避免频繁执行内存申请、复制和删除工作。

②所有的命名中含Ptr的类都不进行删除内存的工作,需要自己完成。

③如果在循环中涉及RemoveAt()函数,循环一定要从尾部开始,否则可能漏掉元素,例:

CTypedPtrArray <CObArray,CPeople*> PeopleArray;

for (int i=PeopleArray.GetSize()-1;i>=0;i--)

    {

    if (PeopleArray.GetAt(i)->Name()=="Tom")

        {

        delete PeopleArray.GetAt(i);

        PeopleArray.RemoveAt(i); //cy: 如果从i=0循环,则删除i后会漏掉对i-1的检查。

        }

    }

List (暂缺)

Map ①由于LookUp的执行速度比较慢,如果必须进行映射,可在第一此LookUp时将其地址获得并记录,此后可直接使用。参考OODBLib/COODBQuery::COODBQuery(),注意

m_cpOODBCDMap=::FhtOODBCDMapOf(aClass.CDMapName());

语句完成了上述操作。

 

 

    下面是MSDNCollections: Choosing a Collection Class章节的一些性能列表及注释。

 

Collection Shape Features

 

Shape Ordered? Indexed? Insert an element Search for specified element Duplicate elements?

List Yes No Fast Slow Yes

Array Yes By int Slow Slow Yes

Map No By key Fast Fast No (keys)

Yes (values)

 

Characteristics of MFC Collection Classes

Class Uses C++ templates Can be serialized Can be dumped Is type-safe

CArray Yes Yes 1 Yes 1 No

CByteArray No Yes Yes Yes 3

CDWordArray No Yes Yes Yes 3

CList Yes Yes 1 Yes 1 No

CMap Yes Yes 1 Yes 1 No

CMapPtrToPtr No No Yes No

CMapPtrToWord No No Yes No

CMapStringToOb No Yes Yes No

CMapStringToPtr No No Yes No

CMapStringToString No Yes Yes Yes 3

CMapWordToOb No Yes Yes No

CMapWordToPtr No No Yes No

CObArray No Yes Yes No

CObList No Yes Yes No

CPtrArray No No Yes No

CPtrList No No Yes No

CStringArray No Yes Yes Yes 3

CStringList No Yes Yes Yes 3

CTypedPtrArray Yes Depends 2 Yes Yes

CTypedPtrList Yes Depends 2 Yes Yes

CTypedPtrMap Yes Depends 2 Yes Yes

CUIntArray No No Yes Yes 3

CWordArray No Yes Yes Yes 3

 

1. To serialize, you must explicitly call the collection object’s Serialize function; to dump, you must explicitly call its Dump function. You cannot use the form ar << collObj to serialize or the form dmp << collObj to dump.

 

2. Serializability depends on the underlying collection type. For example, if a typed pointer array is based on CObArray, it is serializable; if based on CPtrArray, it is not serializable. In general, the “Ptr” classes cannot be serialized.

 

3. If marked Yes in this column, a nontemplate collection class is type-safe provided you use it as intended. For example, if you store bytes in a CByteArray, the array is type-safe. But if you use it to store characters, its type safety is less certain.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值