注:面试过程中整理的学习资料,如有侵权联系我即刻删除。
目录
为什么hashmap是线程不安全的?为什么hashtabe是线程安全的?
数据结构中链表和数组的异同?
数组的元素在内存中是连续存放的,我们可以通过下标快速访问到某个元素,而如果要对数组进行增加或者删除元素,就要移动大量的元素,插入删除的效率低。并且数组的大小是固定的,不能动态扩展。可能浪费内存。
链表的元素在内存中是不连续的,由结点组成,每个结点都包含一个指针域(存储下一个结点的指针)一个数据域。访问链表元素需要从第一个结点开始,遍历找到该结点元素,查找效率低,但是增加和删除元素就很方便,只需要修改结点指针的指向,链表内存利用率很高,大小不固定,扩展很灵活。
<在a、c节点中插入b结点:a->next = b; b->next = c;如果没给出c,那就是b->next = a->next; a->next = b;
删除a的下一个结点:a->next = a->next->next;
delete item;>
所以如果是要快速访问元素,那就使用数组,如果是需要经常删除增加元素,那就使用链表。
队列的数据结构,以及循环(环形)队列如何实现
入队列的时候是队头保持不变,队尾++;
出队列的时候是队尾保持不变,队头++;
循环(环形)队列只要在插入数据的时候对队列容量取余就好了,代表队尾的下一个指向了队头。
队列和栈的使用场景
栈是先进后出,队列是先进先出。
<从左到右打印二叉树的结点是用队列。>
队列:计算机各种资源的管理、消息缓冲器的管理。
栈:匹配表达式的括号(遇到左括号就压栈,遇到右括号就出栈)
以及函数的递归实现。
数据结构中数组、链表、堆栈有些什么区别?
数组是一块连续的内存空间,数据个数是在分配内存时就确定了的。数组的访问的时间复杂度是O(1),查找的时间复杂度是O(N),删除和插入的时间复杂度也是O(N)。
链表是非连续的内存单元,通过指针将各个单元连在一起,链表不需要提前分配固定大小的存储空间,当需要分配内存的时候分配一块内存并把这块内存插入链表中。链表的查找和访问数据的时间复杂度都是O(N),插入和删除数据的时间复杂度都是O(1)。
堆是树形数据结构,每个节点都有一个值,可以说就是一棵树。有二叉树和K叉树堆。堆分为大顶堆和小顶堆<大顶堆的子树也都是大顶堆>。根节点的两个子树也是堆。我们平时常用的堆都是二叉堆,是一个完全二叉树。应用场景包括堆排序、优先队列。
栈是先进后出的结构,对栈的数据操作都只能在顶部,只可以查看、插入、删除栈顶部的数据。(push\pop\top)
队列是先入先出的结构,队列只允许在队头删除数据,在队尾增加数据,但是都可以查看队头队尾的数据。
如何实现哈希表?向后寻址好吗?
<哈希表和数组的查找都是O(1),哈希和数组一样都很耗空间>
哈希表解决冲突有几种方法:开放定址法、链地址法、再哈希法。平时主要用开放定址法。
开放定址法的优缺点:
缺点:a存储记录的数目不能超过桶数组的长度,如果超过了就需要扩容,而扩容会导致时间成本飙升。b使用探测序列,有可能计算key的时间成本很高。c删除记录时,比较麻烦,比如需要删除记录A,记录B是在A之后插入桶数组的,但是和记录A有冲突,是通过探测序列再次跳转找到的地址,所以如果直接删除A,A的位置变为空槽,而空槽是查询记录失败的终止条件,这样会导致记录B在A的位置重新插入数据前不可见,所以不能直接删除A,而是设置删除标记。这就需要额外的空间和操作。
优点:a记录更容易进行序列化操作。b如果预知记录总数,可以创建完美哈希函数,此时的效率很高。
链地址法:
Hashtable
Hashtable是基于哈希表实现的,每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时,会自动增长。Hashtable不允许key和value是NULL的。
Hashtable的put和get方法。
put方法:计算key的hash值,根据hash值获得key在table数组中的索引位置,然后迭代该key处的Entry链表(我们暂且理解为链表),若该链表中存在一个这个的key对象,那么就直接替换其value值即可,否则在将该key-value节点插入该index索引位置处。插入元素时会首先进行容量校验,如果容量已经达到了阈值,hashtable会进行扩容处理rehash()。得到key的hash值主要是通过hashcode函数值与hashseed位与得到的。hashSeed,这是一个实例有关的随机值,主要用来解决哈希冲突。
get方法:处理过程就是计算key的hash值,判断在table数组中的索引位置,然后迭代链表,匹配直到找到相对应key的value,若没有找到返回null。
hashtabe和hashmap的不同
hashtable和hashmap都是STL容器。都是基于哈希表结构的,都是用链地址法来处理的冲突。
- hashtable不允许key和value为null,而hashmap可以。
- 遍历的话两个都可以用迭代器,只是hashtable还可以使用Enumeration方法。
- 在计算hash值时,hashtable用的key的hashcode()来得到,hashmap则是重新计算hash值。
hashtable是线程安全的,hashmap是线程不安全的。
为什么hashmap是线程不安全的?为什么hashtabe是线程安全的?
hashmap不安全:主要是addEntry()函数,多个线程都可以得到当前哈希表位置的头结点,并修改头结点。这样别的线程就会覆盖之前线程的操作。
hashtable安全:是加了锁的,synchronized。
STL之认识hash_set和hash_map
hash_set是限制了功能的hash_map,底层是由hash_map来实现的。对于重复的数据不会再插入。
哈希表的数据检索
哈希表是根据Key---value来直接进行访问的数据结构,以加快查找的速度。是一种寻址容易,插入和删除也容易的数据结构。
哈希表的数据检索,是通过哈希函数。计算出数据所存放的哈希地址。即算出数据在哪个桶的单链中,然后对单链中的每一个数据进行比較,检索出所要的数据。为了使每一个桶中的元素尽可能地少,使用大质数作为表长,并且使用表长作为求余运算的模。
哈希表有多种实现方法,以下是拉链法:
左边是个数组,数组中都是指针,指向一个链表的头,我们根据元素的一些特征把元素分配到不同的链表中去,也是根据这些特征,找到正确的链表,再从链表中找出这个元素。
哈希表是如何存字符串的?
首先将字符串通过哈希算法hash(key)算出对应的哈希值,再取一个大质数取余%,来得到这个字符串所在的key值对应。
哈希算法有非常多,如果是单字符,就可以直接用字符所代表的ASIC码来作为key,字符串abcde可以用97*1+98*E^1+99*E^2+100*E^3+101*E^4来表示这个字符串的key。
什么时候用哈希map,什么时候用map?
两个都是map容器,不同的是key的结构不同。
map的key是红黑树结构(二叉平衡排序树),哈希map的key是哈希表的结构。Hash_map检索出来的元素是无序的,map用迭代器遍历出来的元素是有序的。树结构的查找是O(nlog2n),哈希表结构的查找很快,是O(1)。但是树结构比较有利于插入和删除,所以删除和插入比较多的时候,用map比较好;数据量很大,查询频繁的时候用哈希map比较好。
XML中的节点是什么数据结构
是链表和树,next和pre指针组成链表,children和parent指针组成树。
XML文档的操作其根本原理就是在节点之间移动、查询节点的各项信息,并进行增加、删除、修改等操作。