1. 源码介绍
我们可以看到,set和map的底层是红黑树实现的,但是我们是如何复用红黑树的呢?
红黑树主要看的是第二个参数,它是以第二个参数来创建结点的。
那么第一个参数有什么作用呢?
在我们写的一些函数比如find:
这样的函数需要知道key的类型,所以我们还是要传key的。
在set里面,我们比较key可以直接比较大小。但是map里面是pair,它是怎么比较大小的呢?
库里面是这样去实现的,先比较第一个参数,如果第一个参数不是小于,比较第二个参数。但是我们map需要的是只比较第一个参数,不需要比较第二个参数。这该怎么办呢?而且pair比较是库里面实现的,我们还不能重载。
库里面增加了一个KeyOfvalue,它的作用是取出value对象中key的仿函数。
这样我们去比较大小的时候就可以用这个仿函数来实现复用了。
2. 封装迭代器
这里的迭代器和list的迭代器是类似的,都是需要封装结点的指针了。
此时,我们重点要实现的是++和–这两个函数。
2.1 ++
那么我们该如何实现++呢?
既然是++,那么二叉搜索树遍历是按照中序遍历的。所以解决方法如下:
我们需要判断当前位置结点的右子树是否为空?
不为空:就找右子树的最左结点。
为空:找孩子在父亲左边的那个父亲结点。
假设it在5这个位置,它的右边为空,它在父亲的左边,所以下一个位置是6。6的右边不为空,就找右子树的最左结点,也就是7。7的右边为空,找孩子在父亲左边的那个父亲结点,7在6的右边,不符合,6在7的左边,符合。所以下一个位置就是8。
此时it在15这个位置,15的右边为空,找孩子在父亲左边的那个父亲结点。但是一直找到8,都没找到。然后8的父亲是空,也就结束。
代码实现:
后置++就可以套用一下:
2.2 - -
那么我们该如何实现- -呢?
减减就和加加反着来就行了。
我们需要判断当前位置结点的左子树是否为空?
不为空:就找左子树的最右结点。
为空:找孩子在父亲右边的那个父亲结点。
2.3 进行完善
这里在红黑树里面定义一个普通迭代器和一个const迭代器。
set迭代器定义:
set里面的迭代器都是const修饰的,原因是key不能被修改。
map迭代器就不需要,普通的就调用普通迭代器,const就调用const迭代器。
typename在这里的意思是:
因为我们要取一个类模板的内嵌类型,但是我们不能直接去取,因为还没有实列化。加这个意思是:告诉编译器它是一个类型,等实列化了再去取。
3. operator[ ]
首先,我们需要写一个find函数:
然后,我们需要把insert改造一下:
这里我们需要保存一下cur,因为在翻转的情况下,cur可能会改变。
那么set和map封装的情况如下:
这里set的insert的意思是从const迭代器里面构造一个普通迭代器。
map就不需要因为普通的和const是分开的。
最后我们用insert来完成[ ]: