链表

数组需要一块连续的内存空间来存储,对内存的要求比较高。当内存中没有连续的,足够大的存储空间时,即便内存的剩余总可用空间大于需要的空间,仍然会申请失败。
而链表恰恰相反,它并不需要一块连续的内存空间,它通过“指针"将一组零散的内存块串联起来使用。
在这里插入图片描述
单链表
其中,我们把内存块称为链表的“结点”。为了将所有的结点串起来,每个链表的结点除了存储数据之外,还需要记录链上的下一个结点的地址。我们把这个记录下个结点地址的指针叫作后继指针 next。

在这里插入图片描述
在这里插入图片描述链表访问需要的时间复杂度是O(n)。

循环链表
在这里插入图片描述尾结点指向头结点

双向链表
在这里插入图片描述
如果存储同样多的数据,双向链表要比单链表占用更多的内存空间。
双向链表可以支持 O(1) 时间复杂度的情况下找到前驱结点,正是这样的特点,也使双向链表在某些情况下的插入、删除等操作都要比单链表简单,高效。

在这里插入图片描述在这里插入图片描述在这里插入图片描述
LinkedHashMap的底层就是使用了散列表+双向链表
LinkedHashMap(支持插入顺序遍历数据,也支持访问顺序来遍历数据)
访问,更新,插入操作,都会将结点移动到链表尾部。所以它就是一个LRU缓存淘汰算法。
在这里插入图片描述

双向循环链表
在这里插入图片描述
在这里插入图片描述这里的CPU缓存机制指的是什么?为什么就数组更好了?
CPU在从内存读取数据的时候,会先把读取到的数据加载到CPU的缓存中。而CPU每次从内存读取数据并不是只读取那个特定要访问的地址,而是读取一个数据块(这个大小我不太确定。。)并保存到CPU缓存中,然后下次访问内存数据的时候就会先从CPU缓存开始查找,如果找到就不需要再从内存中取。这样就实现了比内存访问速度更快的机制,也就是CPU缓存存在的意义:为了弥补内存访问速度过慢与CPU执行速度快之间的差异而引入。
对于数组来说,存储空间是连续的,所以在加载某个下标的时候可以把以后的几个下标元素也加载到CPU缓存这样执行速度会快于存储空间不连续的链表存储。

在这里插入图片描述
LRU缓存算法(基于链表实现)
在这里插入图片描述LRU缓存算法(基于数组实现)
思路:维护着一个规定大小的数组,越靠近下标[0]的数据表示越早访问,当有一个新的数据访问时,从0开始遍历到n,
1.找到第k位的已经缓存在链表中的数据,将k+1-n的数据前移一位,将第k位数据插入到第n位。
2.如果没有找到缓存,并且数组未越界,直接最后 的位置加入。
3.如果没有找到缓存,且数据已满,删除第0位,数据前移,加入新的数据。

LRU缓存算法改进(散列+链表)
在这里插入图片描述前驱和后继指针是为了将结点串在双向链表中,hnext 指针是为了将结点串在散列表的拉链中。
查找:散列表中查找数据的时间复杂度接近 O(1),所以通过散列表,我们可以很快地在缓存中找到一个数据。当找到数据之后,我们还需要将它移动到双向链表的尾部。
删除:需要找到数据所在的结点,然后将结点删除。借助散列表,双向链表可以通过前驱指针 O(1) 时间复杂度获取前驱结点,所以在双向链表中,删除结点只需要 O(1) 的时间复杂度。
添加:需要先看这个数据是否已经在缓存中。如果已经在其中,需要将其移动到双向链表的尾部;如果不在其中,还要看缓存有没有满。如果满了,则将双向链表头部的结点删除,然后再将数据放到链表的尾部;如果没有满,就直接将数据放到链表的尾部。
这里所指的尾部应该是散列表的尾部,然后让本来的尾部的next指向当前散列表的链表的尾部。

判断一个字符串是否是回文字符串:(如:abcdedcba)
1 快慢指针定位中间节点
2 从中间节点对后半部分逆序
3 前后半部分比较,判断是否为回文
4 后半部分逆序复原
时间复杂度On, 空间复杂度O1

数组和链表在查找,删除和添加的一些小结。
所以对于面试经常问到的数组和链表,多数的回答是这样的:数组更适合于查找,时间复杂度是O(1),删除和添加都是O(n)。对于链表,更适合于添加和删除,时间复杂度是O(1),查找的时间复杂度是O(n)。
但是以上的讨论应该只是特殊情况,总结如下:
数组:
查找:如果是根据随机访问或者已知下标的情况下,时间复杂度确实是O(1),但是如果查找的是确定的某一个值,时间复杂度是O(n),因为依然需要遍历数组。如果数组是有序数组,查找可以使用二分查找,时间复杂度变为O(logn)。
删除和添加都需要遍历数组:平均时间复杂度O(n),最好时间复杂度位O(1)。
链表:
查找:平均时间复杂度O(n),最好时间复杂度位O(1)。
删除:因为删除的数据是确定的某一个数据,所以需要先遍历数组,找到该结点后,对于单向链表还需要遍历多一次,找到前驱结点,时间复杂度是O(n)。如果双向链表不需要再遍历一次,但是时间复杂度依然是O(n),如果对于单纯的删除操作,那时间复杂度确实是O(1)。
添加:与删除类似。

指针:
将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指针,或者反过来说,指针中存储了这个变量的内存地址,指向了这个变量,通过指针就能找到这个变量。

哨兵

在这里插入图片描述在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值