首页 > 其他分享 >关于CMap的小知识

关于CMap的小知识

时间:2023-09-20 14:45:44浏览次数:42  
标签:Map 知识 元素 pos CMap 关于 哈希 myMap

最近在mfc中用到字典,自己不会在网上查了资料。简单总结一下:
一,CMap是什么?
      映射(Map),又称为字典(Dictionary),是由关键字(Key)及其对应的元素值(Value)所组成的元素单

元(Element)的表单式集合。CMap是一个mfc的模板类,可以建立一个从任意类型的变量到另外一个任意类型的

变量的映射(map),用的是哈希表作存储,因此速度较快。对于要求查找速度快一般用数组,对于增加/删除操作

方便的都用链表,但要是两者综合一下,最好还是用合希表。

 

二,要注意的几个地方:
   1.如何声明CMap
          许多人对Cmap的声明模式CMap<KEY,ARG_KEY,VALUE,ARG_VALUE>感到迷惑,为什么不用CMap<KEY,VALUE> 

   呢?实际上,CMap中的的数据最终会是CPair,而CPair内部是(KEY,VALUE)。因此,CMap其实存储的是KEY

   ,而非ARG_KEY。然而,如果你查看MFC的源代码,几乎CMap所有的内部参数传递都是访问ARG_KEY和ARG_VALUE,因此,使用KEY&来代替ARG_KEY似乎是正确的,除了在这些情况下:
     1 应用简单的数据类型,如int ,char用值传递与参数传递没有什么不同
     2 如果用CString作为KEY,你应该用LPCTSTR做ARG_KEY而非CString&。

  2.有哪些与Map相关的典型操:

  1 向Map中插入具有给定关键字的元素单元。

  2 在Map中查找具有给定关键字的元素单元。

  3 在Map中删除具有给定关键字的元素单元。

  4 枚举(遍历)Map中的所有元素单元。

   
三,简单的例子:
   例子一: 我们来看一个CMap的用法,下面示例代码:

 CMap<int,int&,CPoint,CPoint&> myMap;

 //初始化哈希表,并指定其大小(取奇数)。MyMap.InitHashTable(257);

 //向myMap中添加元素单元。
 for (int i=0;i < 200;i++)
   myMap.SetAt( i, CPoint(i, i) );

  // 删除实际值为偶数的关键字所对应的的元素单元。
 POSITION pos = myMap.GetStartPosition();
 int nKey;
 CPoint pt;
 while (pos != NULL)
 {
  myMap.GetNextAssoc( pos, nKey, pt );

  if ((nKey%2) == 0)
   myMap.RemoveKey( nKey );
 }

 #ifdef _DEBUG
  afxDump.SetDepth( 1 );
  afxDump << "myMap: " << &myMap << "/n";CMap<int,int&,CPoint,CPoint&> myMap;

//初始化哈希表,并指定其大小(取奇数)。MyMap.InitHashTable(257);

//向myMap中添加元素单元。
for (int i=0;i < 200;i++)
 myMap.SetAt( i, CPoint(i, i) );

 // 删除实际值为偶数的关键字所对应的的元素单元。
 POSITION pos = myMap.GetStartPosition();
 int nKey;
 CPoint pt;
 while (pos != NULL)
 {
  myMap.GetNextAssoc( pos, nKey, pt );

  if ((nKey%2) == 0)
   myMap.RemoveKey( nKey );
 }

 #ifdef _DEBUG
  afxDump.SetDepth( 1 );
  afxDump << "myMap: " << &myMap << "/n";


CMap是个很不错的数据结构,尤其在你建立一个字典的时候。比如idcountry的含义是"中国",这就是一个元组

,也就是一个Pair,Key是"idcountry",而Value是"中国"。

例子二:

1、定义一个CMAP,向这个CMAP中增加数据项(键-值对)。
CMap<CString, LPCTSTR, CString, LPCTSTR>m_ItemMap;
CString strKey = _T(""), str = _T("");
int i;
for(i = 0; i < 5; i++)
    {
        strKey.Format("%d", i);              //这个是键
        str.Format("A%d", i);               //键对应的值 
        m_ItemMap.SetAt(strKey, str);
    }
2、遍历正个CMAP的常用方法。
    POSITION pos = m_ItemMap.GetStartPosition();
    while(pos)
    {
        m_ItemMap.GetNextAssoc(pos, strKey, str);
        cout<< strKey<< ":"<< str<< endl;
    }
3、在CMAP中查找相应的数据项。
    CString pReset;
    if(m_ItemMap.Lookup("1", pReset))
    {
        cout<<pReset<<endl;
    }

 

cmap用法,很详细(转)

最新推荐文章于 2021-12-06 11:12:57 发布2071 收藏 1   版权  

一、 Map的基本知识

  MFC中的提供了基于模板的CMap类。利用CMap模板类,可以处理特定的数据类型,例如用户自定义的类或结构体等。同时,MFC也提供了基于指定 数据类型的非模板类,其中包括: 
 

类名 关键字类型 元素值类型
CMapWordToPtr WORDS Void pointers
CMapPtrToWord Void pointers WORDS
CMapPtrToPtr Void pointers Void pointers
CMapWordToOb WORDS Objects
CMapStringToOb Strings Objects
CMapStringToPtr Strings Void pointers
CMapStringToString Strings String

二、 Map的工作原理 

在MFC的CMap及其相关的Map类中,只要对Map进行正确设置,Lookup函数通常能够一次到位的查找到任意元素,而很少需要进行两次或者三 次以上的查找比对。 

struct CAssoc
{
CAssoc* pNext;
UINT nHashValue;
CString key;
CString value;
};

 

nHashTableSize是哈希表中元素的数目(默认情况下,哈希表的大 小为17)。

如果在哈希表中的索引值为i的位置已经容纳了一个CAssoc指针,那么MFC将建立一个单独的CAssoc结构体的链表(List),链表中的第一 个CAssoc结构体的地址被存储到哈希表中,而将第二个CAssoc结构体的地址存储到前一个CAssoc结构体的pNext域,以此类推。

  但是,正如我们先前所讨论的那样,只要正确设置Map,链表中的元素一般就不会超过三个,这就意味着,查找通常可 以在三次元素比对操作之内完成。

三、 优化查找效率

  微软推荐将哈希表的大小设置为Map中所存储元素数目的 110% ~120%,以使得Map的应用性能在内存消耗和查找效率之间取得相对平衡。

在MFC中,指定哈希表大小,可调用InitHashTable()函数:

map.InitHashTable(1200);

从统计学上考虑,用奇数作为哈希表的大小也将有助于减少冲突的发生。因此,初始化一个存储1000个元素的哈希表的InitHashTable() 函数可以如下形式使用:

map.InitHashTable(1201);

同时,在InitHashTable()函数的调用时机上,应该注意的是,该函数应当在map包含有任何元素之前使。如果map中已经包含了一个或者 更多的元素,那么,重新改变map的大小,将会引发断言(Assertion)错误。

尽管MFC中所使用的哈希算法能够适应于大多数场合,但如果您真的有所需要,或者,只要你愿意,用户也可以使用自己的算法来取代原有的算法。对于一个 输入的关键字的值,要计算出它的哈希值,MFC通常调用一个全局模板函数HashKey(),对于大多数数据类型而言,HashKey()函数是以下面的 方式实现的:
 


AFX_INLINE UINT AFXAPI HashKey(ARG_KEY key)
{
//一般情况的默认算法。
return ((UINT)(void*)(DWORD)key) >> 4;
}

但对于字符串而言,其具体的实现方式如下:

UINT AFXAPI HashKey(LPCWSTR key) // Unicode 编码字符串
{
UINT nHash = 0;
while (*key)
nHash = (nHash<<5) + nHash + *key++;
return nHash;
}

UINT AFXAPI HashKey(LPCSTR key) // ANSI编码字符串
{
UINT nHash = 0;
while (*key)
nHash = (nHash<<5) + nHash + *key++;
return nHash;
}


要实现对应于特定数据类型的用户自定义哈希算法,您可以使用上述的字符串版本的HashKey()函数作为参考,写一个类似的特定类型的 HashKey()函数。

 

四、 使用MFC中的CMap类

  构造函数:

CMap 构造一个关键字和元素值映射的集合类。

操作: 

Lookup 通过给定的关键字查找相应的元素值。
SetAt 向Map中插入一个元素单元;若存在匹配键字,则替代之。
operator [] 向Map中插入一个元素 -SetAt的子操作
RemoveKey 移除由关键字标示的元素单元
RemoveAll 移除Map中的所有元素单元
GetStartPosition 返回第一个元素单元的位置
GetNextAssoc 读取下一个元素单元
GetHashTableSize 返回哈希表的大小(元素单元的数目)
InitHashTable 初始化哈希表,并指定它的大小

状态: 

GetCount 返回Map中元素的数目
IsEmpty 检查Map是否为空(无元素单元)

应用实例如下: 


CMap myMap;
//初始化哈希表,并指定其大小(取奇数)。

MyMap.InitHashTable(257);

//向myMap中添加元素单元。
for (int i=0;i < 200;i++)
myMap.SetAt( i, CPoint(i, i) );

// 删除实际值为偶数的关键字所对应的的元素单元。
POSITION pos = myMap.GetStartPosition();
int nKey;
CPoint pt;
while (pos != NULL)
{
myMap.GetNextAssoc( pos, nKey, pt );

if ((nKey%2) == 0)
myMap.RemoveKey( nKey );
}

#ifdef _DEBUG
afxDump.SetDepth( 1 );
afxDump << "myMap: " << &myMap << "/n";
#endif


2、选择适当大小的奇数-- 或者,有可能的话,使用素数的效果会更好一些--来作为哈希表的初始值。 

3、然后,向myMap中添加元素单元。 

4、使用myMap进行数据映射、查找、遍历等操作。 

5、调用myMap.RemoveAll()函数移除所有元素,释放myMap占用的内存空间。 

CMap对应IMPLEMENT_SERIAL,从而支持用户对其元素进行串行化(Serialization)以及倾注(Dumping)操作。在 对CMap的独立元素进行倾注操作时,应该注意的是,你必须将倾注环境(Dump Context)的深度设置为1或者更大的数字。 

标签:Map,知识,元素,pos,CMap,关于,哈希,myMap
From: https://www.cnblogs.com/ioriwellings/p/17717281.html

相关文章

  • 视频存储平台EasyCVR视频关于机电设别可视化管理可实施设计方案
    EasyCVR视频存储平台的机电设备可视化管理方案,通过集成视频采集、数据处理和可视化管理三个模块,实现了对机电设备的全方位、实时监控和管理,大大提高了设备的运行效率和使用安全性。一、EasyCVR平台部署:在需要监控的机电设备周围安装EasyCVR定制的4G车载摄像头,并通过OBD采集设备......
  • 关于 tomcat 集群中 session 共享的三种方法
    前两种均需要使用memcached或redis存储session,最后一种使用terracotta服务器共享。建议使用redis,不仅仅因为它可以将缓存的内容持久化,还因为它支持的单个对象比较大,而且数据类型丰富,不只是缓存session,还可以做其他用途,一举几得啊。 1、使用filter方法存储这种方法比较......
  • 关于.Net 6.0 在Linux ,Docker容器中,不安装任何依赖就生成图形验证码!!!!!!!!!!!
    在.NetFramework时代,我们生成验证码大多都是用System.Drawing。在.Net6中使用也是没有问题的。但是,System.Drawing却依赖于WindowsGDI+。为了实现跨平台,我陷入了沉思!! 微软推荐使用SkiaSharp进行替代,所以就开始了,踩坑之旅首先,安装SkiaSharp 编写好图形生成代码。......
  • 每个.NET开发都应掌握的C#异常处理知识点
    上篇文章讲述了C#集合知识点,本文将介绍C#异常处理知识点。异常处理是.NET开发中至关重要的一部分,它允许开发者在程序出现错误或不正常情况时采取适当的措施,从而提高应用程序的稳定性和可靠性。本文将介绍C#异常处理知识点,异常的基本概念略过,请查看官网。1、自定义异常开发者可以......
  • springframework中关于bean的装配方式、初始化、实例化流程
    ●bean的配置方式?○xml文件配置○bean的配置范围(scope范围)○bean的延迟加载(applicationContext是立即加载,如果需要延迟加载设置lazy-init为true,在getBean的时候才进行加载,加载实例化完了之后回存储到单例池中去,后续使用该bean直接从单例池中获取即可,本质上该bean还是单例的)......
  • 作用域和作用域链的相关知识
    作用域作用域(scope)规定了变量能够被访问的“范围”,离开了这个“范围”变量便不能被访问。作用域分为:局部作用域全局作用域局部作用域局部作用域分为函数作用域和块作用域。函数作用域在函数内部声明的变量只能在函数内被访问,外部无法直接访问。functionfoo(){c......
  • 【C#】【Equals和ReferenceEquals】关于对象和值的问题
    在学习C#中的记录类型时,对出现的Equals和ReferenceEquals得到的不同结果表示不理解,随即进行相关资料查找。 值类型==:比较两者的“内容”是否相同,即“值”是否一样Equals:比较两者的“内容”是否相同,即“值”是否一样ReferenceEquals:返回false,因为会对值类型进行装箱再进行......
  • 关于“VMware ESXi OpenSLP堆溢出漏洞”的修复说明​
    关于“VMwareESXiOpenSLP堆溢出漏洞”的修复说明前段时间IT圈被一个“ESXiArgs勒索软件攻击VMwareESXi服务器”的相关新闻刷屏。互联网上的文章称,这些攻击活动似乎利用CVE-2021-21974漏洞,由OpenSLP服务中的堆溢出问题引起,未经身份验证的威胁参与者可以利用该问题进行低复......
  • 关于类main方法的使用
    classTest{publicstaticvoidmain(String[]args){Tt=newT();t.m();}}publicclassT{publicvoidm(){System.out.println("类T");}}在doc命令下运行 采用命令javac T.java 和 java Test运行即可成功......
  • 关于三次多项式复合的一个注记
    首先根据熟知的变换,复合\(f(ax^3+bx^2+cx+d)\)的问题的困难内核在于\(f(x^3+cx)\),在域上,只要解决某个\(c\neq0\)的情况,就解决了一般的情况.取\(c=-3\),我们有\[x^3-3x=(x^3+x^{-3})\circ(x+x^{-1})^{\langle-1\rangle}.\]于是问题的难点转换成了计......