数据结构和算法之美

 

06链表上:如何实现LRU缓存淘汰算法?

1 链表vs数组:

二者的区别首先在插入删除和随机访问的时间复杂度

数组简单易用,使用连续的空间,可以借助CPU的缓存机制,预读数组中的数据,访问效率高;

而链表在内存中不是连续存储,对CPU缓存不友好,没办法有效预读。

数组的缺点是大小固定,一经声明就要占用整块连续内存空间。如果过大,浪费内存,如果过小,可能不够用。这时只能再申请一个更大的空间,把原数组拷贝进去,非常费时;而链表天然支持动态扩容。

07链表下

1.常见的检查链表代码是否正确的边界条件:

链表为空时是否正确?

链表只包含一个节点时是否正确?

链表只包含两个节点时是否正确?

处理头节点和尾节点时是否正确?

2.链表题目:206,141,21,19,876

单链表反转

链表中环的检测

两个有序的链表合并

删除链表倒数第 n 个结点

求链表的中间结点

08.如何实现浏览器的前进和后退

1.栈的实现:可以用数组,可以用链表

2.栈的应用:

函数调用:

表达式求值:

通过两个栈实现,一个用来保存操作数,另一个用来保存运算符;

从左到右遍历表达式,遇到数字,就直接压入操作数栈,当遇到运算符,就与运算符栈的栈顶元素进行比较;

如果比运算符栈顶元素的优先级高,就将当前运算符压入运算符栈,如果比运算符栈顶元素的优先级低或者相同,从运算符栈中取栈顶运算符,从操作数栈的栈顶取2个操作数,然后进行计算,再把计算完的结果压入操作数栈,继续进行和运算符栈顶元素的比较;

如下图:

括号匹配:

浏览器的前进和后退:

用两个栈实现,X和Y,首次浏览的页面一次压入栈X,当点击后退按钮时,再依次从栈X中出栈,并将出栈的数据依次放入栈Y中。

当点击前进按钮时,再依次从栈Y中取出数据,放入栈X中。

当栈X中没有数据时,就说明没有页面可以继续后退浏览了。

当栈Y中没有数据时,就说明没有页面可以继续前进浏览了。

注:栈X中的栈顶元素是当前浏览的页面。

09.队列:队列在线程池等有限资源池中的应用

循环队列:

阻塞队列:

在队列的基础上增加了阻塞操作。

当队列为空,从队头读数据会被阻塞,直到队列中有数据;

当队列已满,从队尾插入数据会被阻塞,直到队列中有空位置。

阻塞队列可用于实现生产者消费者模型。

但是当有多个线程同时操作时,会存在线程安全问题。

并发队列:

线程安全的队列叫做并发队列。最简单的实现方式是入队和出队的时候加锁。

问题:当线程池没有空闲线程,新的任务请求线程资源时,线程池如何处理呢?

方法1:非阻塞的处理方式,直接拒绝任务请求;

方法2:阻塞的处理方式,将请求排队,当有空闲的线程时,取出排队的请求继续处理。那么怎样存储排队的请求呢?

有两种方式:

1.基于链表的实现方式,实现一个支持无限排队的无界队列,但可能导致过多的请求排队等待,请求处理的响应时间过长。

2.基于数组实现的有界队列,超过队列大小时,拒绝接下来的请求。

猜你喜欢

转载自blog.csdn.net/m0_38062470/article/details/115377644