1.看源码,简单了解原码的set和map类的结构
1.看类的私有成员和类模板的参数:
看下面我画的一些框,再结合上面的看一下,会有什么疑惑呢?
一般我们知道编译器底层的代码会很简洁,不会多创建无意义的内容,但是这set的成员变量,竟然传了两个Key给红黑树,这是怎么回事呢?难道是为了和map一样,Key和vlaue来浪费set的一个模板嘛?不确定,我们还是再看一下map是怎么存储的吧。
中间有太多暂时不需要的,我简单删一下:
看到这里应该就明白了,无论是set还是map,编译器都多传了一个key的模板参数给红黑树,这是为什么呢?
其实仔细想想就会明白,比如find函数,我们在红黑树里面怎么定义?如果没有第一个参数模板,那map中find函数应该是bool find(const K& key)那K这个类型怎么来?如果只传pair的话,就无法弄出来了,所以我们就必须传两个参数一个key还有一个是pair类型。
2.最后其实还差一个东西要先了解一下,下面还会详细讲,这边先有一个印象:
那么就剩下我红色框的那个模板类型了,其实这个就是和compare一样的,就是一个仿函数,那这个的作用是什么呢?其实就是map中获取pair中first的key成员,而set这边主要就是陪跑的,为了兼容map而存在的。下面有具体的实现,原码里的还是有点复杂的,现在看没必要。
2.模拟实现map和set
1.模拟实现红黑树
这边作者就不详细讲了,可以看:
1.红黑树的结点:
如果是set的话就是T就是K, 是map的话,T就是pair<K, V>.
这边Color其实一个枚举,方便表示罢了。
2.红黑树的主体部分
作者这边只模拟实现了前三个模板参数
2.下面是成员函数:
2.封装map和set
1.set
1.可以先讲一下迭代器,无所谓的,值得注意set的迭代器是iterator和const_iterator其实都是const_iterator迭代器,这就是追究到set的key本来就不支持修改,不然就破坏了红黑树的结构了。
2.map
这个也一样,map中的key是不允许改变的,而value是允许改变的,所以我们可以将key const化就可以达到目的了。
3.实现迭代器
这个就和list迭代器差不多了,创建一个迭代的类,然后慢慢实现迭代的内容:
最难的operator++和--看一下我的函数,画一个图就差不多能理解了,我这边的end函数就是nullptr来结束的,但是源码其实还复杂一点,就是在红黑树的头加了一个header的指针,加了的话,那红黑的插入和删除也要重新改结构,我们模拟只是大概理解底层的实现原理,作者这边就不实现啦,感兴趣的同学可以自行的再去研究研究。