数据结构和算法学习笔记-数组、链表(上)

免责声明,本文内容大多是对数据结构与算法之美课程的学习笔记,内容上面有很多相似之处。也不太适合初学者去直接学习和掌握,仅供有算法经验的同学提供一些,快速回顾算法知识的支持

数组

关键词:线性表(Linear List)、非线性表

定义:

数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。

特性:

优点:随机访问
缺点:删除、插入为保证连续性,需要大量数据搬移工作
访问时间复杂度O(1),插入删除时间复杂度O(n)

常见理解错误:

"链表适合插入、删除,时间复杂度O(1);数组适合查找,时间复杂度O(1)"

实际上,这种表述是不准确的。数组是适合查找操作,但查找的时间复杂度并不是O(1)。即便是排好序的数组,你用二分查找,时间复杂度也是O(logn)。所以正确的表述应该是,数组支持随机访问,根据下表随机访问的时间复杂度为O(1).

容器能否完全代替数组?

ArrayList最大的优势就是可以将很多数组操作的细节封装起来。还有动态扩容的支持

思考题:

1.基于数组的原理引出JVM的标记清除算法的核心理念。回顾一下你缔结的标记清除垃圾回收算法。
2.通过一维数组的内存寻址公式,思考一下二维数组的内存寻址公式

拓展:

除了数组,链表、队列、栈也是线性表结构。
二叉树、堆、图是非线性表

链表(上)

缓存淘汰策略?

先进先出FIFO(First In,First Out)、最近最少使用LFU(Least Frequently Used)、最近最少使用LRU(Least Recently Used)

三种常见的链表结构?

单链表、双向链表和循环链表
对于双向循环链表结合需要自行了解

特性:

删除、和插入时间复杂度O(1) ,访问时间复杂度O(n)

循环链表是一种特殊的单链表,尾结点的指针指向头结点(课下了解:约瑟夫问题)

单链表的插入、删除操作的时间复杂度已经是O(1)了,双向链表还能再高效呢?

实际上这种说法是不准确的,或者说是有先决条件的。
比如:我们希望在链表的某个指定结点前插入一个结点。
另外对于有序链表,双向链表的按值查询效率也要比单链表高一些。因为,我们可以记录上次查找的位置p,每次查询时,根据要查找的值与p的大小关系,决定是往前还是往后查找,所以平均只需要查找一般的数据。
空间换时间

如何使用单链表来实现LRU缓存算法?

维护一个有序单链表,越靠近尾部结点是越早之前访问的。当有一个新数据被访问时候,我们从链表头开始顺序遍历链表。
1.如果此数据之前已经被缓存在链表中了,我们遍历得到这个数据对应的结点,并讲其从原来的位置删除,然后再插入到链表的头部
2.如果此数据没有在缓存链表中,可以分为两种情况:
如果此时缓存未满,则将此结点直接插入到链表的头部;
如果此时缓存已满,则链表尾结点删除,将新的数据结点插入链表的头部。
这样就可以用链表实现LRU缓存了。

课后练习:如何用数组实现LRU缓存淘汰策略?

课后思考:

如何判断一个字符串是否是回文字符串的问题?
如果字符串是通过单链表来存储的,你改如何判断是一个回文呢?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章