为什么会出现hash table,如果是用数组存储数据,如果想要找到其中一个数据,需要从头进行遍历,因为不知道这个数据存储到了数组的哪个位置。使用链表也是,需要从头节点或者尾节点开始进行遍历。
如果在存储一个数据的时候,就知道它的位置,那么在查找的时候就直接根据这个位置去找这个数据。hash表就实现这样一个功能,但是因为如果不同的值映射到了一个位置,那么根据这个位置去找就找不到唯一的值,这就是哈希冲突,解决的办法就是拉链法,同样先创建一个哈希表。
使用malloc函数分配一块在虚拟内存上连续的空间,空间的大小就是需要的存储地址的个数,然后对应的数值存储进去,拉链法可以解决哈希冲突。
但是STL中的map封装的是红黑树,元素是pair(key,value),这里,要求输入的每个key值是可以进行排序的,当输入key值和对应的value(要存储的数据)会对这个value通过红黑树的方式进行排序。当查找的时候,根据value找到对应的key值,然后在log(n)的时间内可以找到该节点。这里的map跟hash_map是不一样的。还有,hash_map的查找不一定是o(1),在有哈希冲突进行拉链的方式的时候,需要遍历链表。
对于一个数组,如果不知道它的下标,那么需要从头开始遍历,查找出这个元素。时间复杂度仍然是O(n),如果已经知道下标,通过a[i]可以直接找到这个数据。但对于链表来说,即使知道节点所在的位置,也需要从头节点开始找,时间复杂度仍然是O(n),但是对于对于哈希表,可以直接根据地址来找到这个元素。
数组与链表的区别:
(1)存储空间上:
链表存放的内存空间可以是连续的,也可以是不连续的,数组则是连续的一段内存空间。一般情况下存放相同多的数据时,数组占用较小的内存,而链表还需要存放其前驱和后继的空间。
(2)长度的可变性:
链表的长度是按实际需要可以伸缩的,而数组的长度是在定义时要给定的,如果存放的数据个数超过了数组的初始大小,则会出现溢出现象。
(3)查找效率:
- 按序号查找时,数组可以随机访问,时间复杂度为O(1),而链表不支持随机访问,平均需要O(n);
- 所以说,数组的时间复杂度为o(1),是有限制的,也就是如果给了下标,就找这个下标的数字,那么可以1内找到,但是对于链表,即使有这个位置,也需要从头开始进行遍历。
-
按值查找时,若数组无序,数组和链表时间复杂度均为O(n),但是当数组有序时,可以采用折半查找将时间复杂度降为O(logn);
(4)插入删除时:
数组平均需要移动n/2个元素,而链表只需修改指针即可;
(5)空间分配方面:
(静态)数组从栈中分配空间, 对于程序员方便快速,但是自由度小。
链表从堆中分配空间, 自由度大但是申请管理比较麻烦。
哈希表结合了数组的快速查询的优点又能融合链表方便快捷的增加删除元素的优势