拿捏小算法——栈和队列

        栈就像一个一边封闭一边开口的圆筒,第一个进去的在最底部,也叫栈底,最后一个进去的在最上面,也叫栈顶;出栈的话,最上面的先出,最下面的后出,也就是先进后出。

入栈

        因为栈底是封闭的,所以入栈的元素进去后就会成为新的栈顶。

出栈

        同样出栈也只能从栈顶出,出来后,原来栈顶的前一个元素就会成为新的栈顶。

队列

        队列可以想象为一个隧道,第一个进去的在队头,最后一个进去的注意不是队尾,而是最后一个元素的下一个是队尾,(如下图)出队的话,自然的就是第一个进去的先出来,最后一个进去的后出来,也就是先进先出。

入队

        就是把新元素放入队列中,只允许在队尾的位置放入元素,新放入的元素的下一个位置自然地成为新的队尾。

出队

        因为队列的先进先出,出队只能从队头先出,队头后面的元素自然的成为新的队头。

如果这样不断地出队,那队头左边的空间就失去作用,队列的空间就会越来越小,就像下面这样

用数组实现的队列采用循环队列的方式来维持队列容量的恒定,如下:

        假如一个队列经过反复的入队和出队操作,还剩下两个元素,在数组不扩容的前提下,让队尾指针重新指回数组的首位,当有新的元素进来时,将其放入数组的首位,队尾指针继续后移即可,过程如下图:

由图可以看出,队尾指针指向的位置永远空出一位,所以队列的最大容量比数组长度小1。

哈希表

        也叫散列表,这种数据结构提供了键(key)和值(value)的映射关系,只要给出一个key,就可以迅速查找出它所匹配的value。

        那么是怎么通过key快速找到value呢?这里用到了哈希函数,类似一个中转站,通过这种方式,把key和数组下标进行转换。如下图:

先暂时不了解哈希函数的原理。

哈希表的写操作

        在Java中,写操作就是在哈希表中插入新的键值对(JDK中叫做Entry),如调用hashMap.put("002931","张三"),意思就是插入一组key为002931,value为张三的键值对。

具体过程是:

        1.通过哈希函数把002931转换成对应的下标,假如是5。

        2.如果下标5对应的位置没有元素,就把Entry填入到下标为5的位置。

但是数组的长度是有限的,当填入的Entry越来越多时,不同的key通过哈希函数转换的下标可能是相同的,这种情况就是哈希冲突。有两种解决方案,一是开放寻址法,二是链表法。

一:

其实就是,以上面转换成下标5为例,如果下标5的位置有元素,那就向后移动一位,看下标为6的位置是否为空,若还为空,就再向后移动一位,看下标7是否为空,若不为空,就存入下标为7的位置。

二:

链表法被应用在Java的集合类HashMap中,HashMap数组的每一个元素不仅是Entry对象,还是一个链表的头结点,每一个Entry对象通过next指针指向下一个Entry节点,当冲突时,只需要插入到对应的链表中即可。如图:

哈希表的读操作

        调用 hashMap.get("002936"),意思是查找Key为002936的Entry在散列 表中所对应的值。

第1步:通过哈希函数,把Key转化成数组下标2。

第2步:找到数组下标2所对应的元素,如果这个元素的Key是002936,那么就 找到了;如果这个Key不是002936也没关系,由于数组的每个元素都与一个链表对应,我们可以顺着链表慢慢往下找,看看能否找到与Key相匹配的节点。如图:

        在上图中,首先查到的节点Entry6的Key是002947,和待查找的Key 002936不 符,接着定位到链表下一个节点Entry1,发现Entry1的Key 002936正是我们要寻 找的,所以返回Entry1的Value即可。

扩容

        当经过多次元素插入,散列表达到一定饱和度时,Key映射位置发生冲突的概率 会逐渐提高。这样一来,大量元素拥挤在相同的数组下标位置,形成很长的链表, 对后续插入操作和查询操作的性能都有很大影响。

        小结

        栈是一种线性逻辑结构,可以用数组实现,也可以用链表实现,遵循先入后出规则。

        队列也是一个种线性逻辑结构,可以用数组实现,也可以用链表实现,遵循先入先出规则。

        哈希表也叫散列表,是存储Key-Value映射的集合,通过哈希函数实现Key和数组下标的 转换,通过开放寻址法和链表法来解决哈希冲突。

Ending: 

        OK,本篇文章就到此结束了,非常感谢你能看到这里,所以如果你觉得这篇文章对你有帮助的话,请点一个大大的赞,支持一下博主,若你觉得有什么问题或疑问,欢迎私信博主或在评论区指出~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值