极客讲堂 - 数据结构与算法之美 - 复杂度分析,数组,链表,栈,队列,递归

03 | 复杂度分析(上) **

1. 复杂度O(n)表示的是单位代码执行时间T(n) 随数据规模n增长的变化趋势

2. 分时间复杂度和空间复杂度(表示存储空间大小)

3. 常见的复杂度并不多,从低阶到高阶有:O(1)、O(n)、O(nlogn)、O(n2 )

4. 有两个增长数据时,如果是嵌套关系,就是O(m*n),是并列关系时,就是O(m+n)

04 | 复杂度分析(下)*

1. 时间复杂度分为: 最好情况时间复杂度, 最坏情况时间复杂度, 平均情况时间复杂度, 均摊时间复杂度。

    同一段代码,在不同输入的情况下,复杂度量级有可能是不一样的.

2. 均摊时间复杂度就是一种特殊的平均时间复杂度。定义:

     对一个数据结构进行一组连续操作中,大部分情况下时间复杂度都很低,只有个别情况下时间复杂度比较高,而且这些操作之间存在前后连贯的时序关系。

05 | 数组 ***

1. 线性表: 数据排成像一条线一样的前后关系的结构。 包括:数组,链表、队列、栈

    非线性表: 数据之间并不是简单的前后关系。包括:二叉树、堆、图。

2. 链表适合插入、删除,时间复杂度 O(1)

    数组适合查找,数组支持随机访问,根据下标随机访问的时间复杂度为 O(1)

3. 数组用连续的内存空间, 来存储相同类型的一组数据。

    最大的特点就是支持随机访问,但插入、删除操作也因此变得比较低效,平均情况时间复杂度为O(n)。

4. 在业务开发中,可以使用编程语言提供的容器类;在底层的开发, 使用数组效率更高

06 | 链表(上) **

1. LRU 缓存淘汰策略, 就是把最近使用过的数据,放在最前面。

2. 为实现LRU 缓存淘汰策略,涉及数据的插入和删除。所以使用链表的数据结构,比数组更合适。

3. 链表分: 单项链表,双向链表、循环链表、双向循环链表。 复杂链表的思路是空间换时间。

4. 数组可以有效利用CPU缓存,但链表不可以

07 | 链表(下) **

1. 要写出无BUG的单向链表的代码,要注意以下几种情况下,能不能正常工作:

(1) 链表为空时

(2) 链表只有一个结点时

(3) 链表只有两个结点时

(4) 代码逻辑在处理头结点和尾结点的时候,是否能正常工作

(5) 主要实现的函数是:头部、尾部指定位置添加结点,删除节点,获取指定位置结点。(遍历链表的方式实现)

2. 可以使用哨兵的方法来规避复杂情况,具体流程是: (非重点)

//(1) 处理好最后一个元素的逻辑

//(2) 用哨兵替换掉最后一个元素,哨兵是一个必定能触发跳出循环的元素。

//(3) 只考虑哨兵跳出,不考虑边界跳出,直接执行逻辑。

在队头添加哨兵元素(不存储数据),当逻辑遇到哨兵时,什么都不用判断,直接退出。

这样就无论插入还是删除结点,逻辑都一样。因为首结点是哨兵,首结点以外的逻辑都一样。

3. 5个练习链表代码能力的例子:

(1) 单链表反转。 遍历链表,修改结点的next成员变量的指向,修改head指针。

(2) 链表中环的检测。用两个指针遍历链表,一个指针每次走一步,另一个指针每次走两步。

(3) 两个有序的链表合并。 另建一个链表头,然后循环比较两链表的结点,取小的插入新链表尾。

(4) 删除单向链表倒数第 n 个结点。 用两个指针,一个指针先走n步,然后两指针齐头并进。先走的指针比后走指针快n步,当先走指针到达链尾时,后走指针就是倒数第n个结点。

(5) 求链表的中间结点。用两个指针,一个指针每次走一步,另一个每次走两步。快指针到达链尾时,慢指针就在中间。

4. LRU缓存淘汰法要点

(1) 如果数据已经在链表中,就把原来位置的结点删除掉,然后插入到链表头部。

(2) 如果数据不在链表中,并且链表未满,就插入到链表头部。

(3) 如果数据不在链表中,并且链表已满,就删除尾部结点,然后插入到链表头部。

08 | 栈 **

1. 如何实现浏览器的前进和后退功能

(1) 使用两个栈X和Y,访问的页面依次入栈X

(2) 页面后退时,X出栈、Y入栈;页面前进时,X入栈,Y出栈

(3) 访问新页面时,X入栈,Y栈清空

09 | 队列 *

1. 线程池没有空闲线程时,新的任务请求线程资源时,线程池该如何处处理?

(1) 非阻塞的处理方式,直接拒绝任务请求

(2) 阻塞的处理方式,将请求排队,等到有空闲线程时,取出排队的请求继续处理。即,使用队列。

2. 为解决队列数据搬移的问题,可以使用循环队列。当队满时,(tail+1)%n=head

3. 阻塞队列就是入队、出队操作可以阻塞

4. 并发队列就是队列的操作多线程安全

10 | 递归 *

1. 满足“三个条件”的问题就可以通过递归代码来解决

(1) 一个问题的解可以分解为几个子问题的解

(2) 子问题,除了数据规模不同,求解思路完全一样

(3) 存在递归终止条件

2. 递归的好处:简洁高效

3. 递归的坏处:

(1) 堆栈溢出,不容易计算堆栈深度,确保安全。

(2) 重复计算,可以通过一个数据结构(比如散列表)来保存已经求解过的 f(k)来避免问题。

(3) 函数调用耗时多

(4) 空间复杂度高

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值