数据结构逆向分析-Map

map是一个典型的二叉树结构,准确的来说是一个平衡二叉树或者红黑树,特点是数据存储是有序的存储。

参考侯杰老师的stl源码剖析,map里面采用的是RB-TREE也就是红黑树

 

 

map存储的数据是以键值对的形式来存储的,Key:Value

 

优势:查找数据效率高,因为是平衡二叉树

缺点:插入数据效率低,因为要插入后变成平衡二叉树。

 

 

 

开始分析:

采用比较简单的代码:

#include<map>
using std::map;
using std::pair;

int main()
{
map<int, int> MyMap;
int SizeMap = sizeof(MyMap);
MyMap.insert(pair<int, int>(1, 100));
MyMap.insert(pair<int, int>(2, 300));
MyMap.insert(pair<int, int>(3, 150));
MyMap.insert(pair<int, int>(4, 200));
MyMap.insert(pair<int, int>(5, 170));
MyMap.insert(pair<int, int>(6, 180));
MyMap.insert(pair<int, int>(7, 90));




return 0;
}

 

 

然后画图表示一下:这就是初始化一个map的内存图,从分析stl的经验上来看MyMap中的第一个指针指向的这个0081e5f8又指回去了好像stl容器都有个这个东西,猜测来讲没啥用。然后这个后面的0081F5F8很有可能是一个指向整个平衡二叉树的头,然后第三个000很有可能就是一个size来记录节点的个数,当然这是我们的猜测,还要看内存来说话。

 

 

执行第一条插入指令:

    MyMap.insert(pair<int, int>(1, 100));

成了这样:

 

 

再来猜测一下,首先这个MyMap的第一个字段肯定是没啥用了,然后最后一个字段确实是里面的大小,然后第二个字段指向的内容,很有可能是指向来了根节点,然后节点的内容里面,最后两个字段是来存放 key->value键值对的。有一些字段暂时不知道有啥用,继续往下弄几个看看。

 

执行第二条和第三条指令:

    MyMap.insert(pair<int, int>(2, 300));
MyMap.insert(pair<int, int>(3, 150));

首先这里的平衡二叉树应该是这样的:

 

 

如果所有箭头都标出来会比较乱,所以这里只用了一些关键的:

 

 

由此可以推出来,这个map第二个字段指向的应该是一个总领作用的结构体,其中第二个字段指向的是平衡二叉树的根节点,然后第一个和第三个字段是什么意思暂时不知道,最后一个结束字段的0101也不知道,然后数据节点的话,通过对根节点猜测,第一个字段应该指向的是左节点,第三个字段指向的是右节点。

目前的结果是这样:

 

 

再参考侯杰老师的stl源码剖析书后:

 

 

可以确定很多东西了:

 

 

根据侯杰老师的定义重新写代码分析:

由于目前只有cdcd后面哪两个字节的内容不知道了,这里我选择根据官方书重新写代码来观察这个字段的内容:

#include<map>
using std::map;
using std::pair;

int main()
{
map<int, int> MyMap;
int SizeMap = sizeof(MyMap);
MyMap.insert(pair<int, int>(5, 100));
MyMap.insert(pair<int, int>(6, 300));
MyMap.insert(pair<int, int>(8, 150));
MyMap.insert(pair<int, int>(7, 200));
MyMap.insert(pair<int, int>(11, 170));
MyMap.insert(pair<int, int>(10, 180));
MyMap.insert(pair<int, int>(12, 90));
MyMap.insert(pair<int, int>(13, 400));
MyMap.insert(pair<int, int>(15, 400));


return 0;
}

这里画图太麻烦,我只画比较关键的内容了:

 

 

可以看到内容只有0和1,我测试是平衡二叉树的平衡因子,但是不对,如果是平衡因子的画13为啥是0001,由于这个底层是红黑树,所以这里我猜是用来标记红黑的。

红黑树的性质:

规则1:节点是红色或黑色的;
规则2:根节点是黑色的;
规则3:每个叶子节点都是黑色的空节点(NIL节点);
规则4:每个红色节点的两个子节点都是黑色的(从每个叶子到根的所有路径上不可能有两个连续的红色节点);
规则5:从任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点;
将红黑树的节点默认颜色设置为红色,是为尽可能减少在插入新节点对红黑树造成的影响。

也就是说8肯定是黑色,那么默认是红色的情况下6,11是红色,而红色不能连续,红色的子节点必须是黑色,则5,7,10,13肯定是黑色,而默认是红色,且不会影响别的那么12,15也就是红色。

破案了:情况非常吻合,红色为0000,黑色为0001。