C++模拟实现unordered_map和unordered_set

目录

1.了解哈希表

1.哈希表

1.他的实现原理就是:        ​编辑

2.写单个数据的类型(这边先模拟map的kv类型,后面会再一起改,这边先一步步的先简单实现他)

3.封装整个类:

4.哈希表中存储string

2.哈希桶

3.封装unordered中的哈希桶

4.迭代器的实现

5.封装unordered_map和unordered_set


1.了解哈希表

其实了解这两个库,就知道底层其实是一个哈希表的一个功能。所以我们首先要了解哈希表。

        他其实就是解决在一堆数据里,取寻找某一个数据在不在的一个问题。想想如果让他先排序,然后在找,排序的时间复杂度其实很大了,那有没有办法用o(N)的时间复杂度将这个数据拷贝下来,在以后查找这个数据在不在,时间复杂度都是在0(1)呢?

        其实这个就是哈希实现的功能。

1.哈希表

1.他的实现原理就是:
        C++模拟实现unordered_map和unordered_set_第1张图片

注意看这个18这个数字是不是和2这个位置冲突了,所以我们需要往后面移一个位置,那我们找也一样,也是要往后找,那找到什么时候结束?(就是找到空格结束,还没有找到就是没有;或则最坏的结果就是把这个数组都找完,因为这个数组都填满了这个数据,但是这个情况不会发生,因为我们在写这个底层是,会不断的给他扩容。你想想看,如果都快填满了,那查找它的效率就会明显下降,那就失去了他高效功能的意义了)

2.写单个数据的类型(这边先模拟map的kv类型,后面会再一起改,这边先一步步的先简单实现他)

我上面讲的数组除了存储它的数据,但我举一个例子:

C++模拟实现unordered_map和unordered_set_第2张图片

如果我们删除6,再去寻找44就找不到了,所以我们就需要一个状态值了:

C++模拟实现unordered_map和unordered_set_第3张图片

所以我们就可以开始第一步了:
C++模拟实现unordered_map和unordered_set_第4张图片

3.封装整个类:

先看成员变量:
C++模拟实现unordered_map和unordered_set_第5张图片

现在来讲解上面HashFunc是干嘛用的,他其实是一个仿函数,为什么需要仿函数呢?你要知道我们不知道key中存的是什么数据,可以无法整除整数,那就和哈希完全不相关联,所以我们要引入这个模板,当其他人使用这个类时,想存储自定义类型也是可以的,只需要让他写一个仿函数就可以了。

C++模拟实现unordered_map和unordered_set_第6张图片

最后还有一点就是扩容不能超过0.7,其实每一个库实现的都不一样,这边其实没有一个统一的划分。

4.哈希表中存储string

这个为什么要单独拿出来讲呢?因为这个会出错:因为字符串转化为整形,很有可能会重叠,所以大佬们也是想了很多办法,但也只能不断地减小误差。

各种字符串Hash函数 - clq - 博客园 (cnblogs.com)

可以去这个网站上了解一下:
C++模拟实现unordered_map和unordered_set_第7张图片

我就用最高评分的那种了:

就用一个模板的特例化取解决:
C++模拟实现unordered_map和unordered_set_第8张图片

2.哈希桶

        C++模拟实现unordered_map和unordered_set_第9张图片

能明白我的意思把,就是这个数组变成了指针数组,下面是一个链表,只有next的链表。但是库里面比我这个模拟实现还要复杂,下面挂的不是单链表,而是红黑树,其实也不是很难实现,有兴趣的可以自己实现一下:
 

3.封装unordered中的哈希桶

这是单个数据的结点:

C++模拟实现unordered_map和unordered_set_第10张图片

下面这个我就先连迭代器一起写进去了,还有一些知识因为在set和map模拟里面我有说过,这些基本是一样的,我就不累赘了,C++模拟实现set和map-CSDN博客

C++模拟实现unordered_map和unordered_set_第11张图片

4.迭代器的实现

其实在我们模拟实现中,不应该按照我这个顺序来的,这在set和map那节也说过,这是因为我是已经模拟完了,才过来写这篇博客的。其实正确的模拟顺序是:

1.模拟实现哈希桶

2.初步封装unordered_map和unordered_set。

3.模拟实现迭代器

4.在迭代器中加入const迭代器

5.insert返回值, operator[]

6.map中的key和set不能修改的问题

如果一起直接写完,那必然很容易就会报错,那么就会让你很无从下手,甚至想放弃。

然后我们继续说迭代器。这个迭代器还是比较特殊的。

C++模拟实现unordered_map和unordered_set_第12张图片

首先一点就是,我们要想清楚,我们成员变量只有一个Node* 的结点指针是否就够了,看上面那张图,如果结点指针指向了44,我们怎么跳到5?因为我们这个结点只有next,所以只能找到下一个,不能找到上一个,那执行oeprator++就不怎么好执行了,所以我们必须要再加一个成员变量,这个哈希桶的头指针。

C++模拟实现unordered_map和unordered_set_第13张图片

但现在其实还有一个问题,我们下面的迭代器类需要_table, HashTable类需要iterator,这个相互牵扯的,每一个类都在在另一个类上面去实现他。所以就需要声明一个类了。

C++模拟实现unordered_map和unordered_set_第14张图片

所以:

C++模拟实现unordered_map和unordered_set_第15张图片

而且,迭代器中的_pht需要拜访_table,所以还要加一个友元:
C++模拟实现unordered_map和unordered_set_第16张图片

最后看一下整体的:
C++模拟实现unordered_map和unordered_set_第17张图片

5.封装unordered_map和unordered_set

C++模拟实现unordered_map和unordered_set_第18张图片C++模拟实现unordered_map和unordered_set_第19张图片

你可能感兴趣的:(c++,哈希算法,散列表)