文章目录

  • 大纲图
  • 链表的经典面试题目
    • 如何设计一个LRU缓存淘汰算法
    • 约瑟夫问题
  • 顺序表VS 链表
  • 链表的定义
  • 链表的特点
  • 常见的链表结
  • 单向链表
    • 单向链表的查找
    • 单向链表的插入
      • 头插
      • 尾部插入
      • 中间插入
    • 单向链表的删除
      • 删除头节点
      • 删除中间的节点
      • 删除尾部节点
    • Code
  • 总结


大纲图


链表的经典面试题目

如何设计一个LRU缓存淘汰算法

tip:单向链表


约瑟夫问题

N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。

举个例子: 假设N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。
现在问你最后留下的人是谁?
比如N=6,M=5 ,留下的就是1

1 2 3 4 5 6 => 6 1 2 3 4 => 6 1 2 3 =>1 2 3 => 1 3 => 1

tips: 单向循环链表


顺序表VS 链表


链表的定义

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。

每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 比如下面这种

相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。

使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。


链表的特点

  • 不需要连续的内存空间
  • 有指针引用

常见的链表结

三种最常见的链表结构:单向链表、双向链表 和循环链表 (单向循环链表、双向循环链表)


单向链表

单向链表是由一个个节点组成的,每个节点是一种信息集合,包含元素本身以及下一个节点的地址。

从单链表图中,可以发现,有两个结点是比较特殊的,它们分别是第一个结点和最后一个结点。

我们一般把第一个结点叫作头结点,把最后一个结点叫作尾结点。

其中,头结点用来记录链表的基地址。有了它,我们就可以遍历得到整条链表。

而尾结点特殊的地方是:指针不是指向下一个结点,而是指向一个空地址NULL,表示这是链表上最后一个结点。


单向链表的查找

没啥好说的,从头结点开始遍历,直到找到停止,不存在的话,就是全部遍历了,查找的时间复杂度为O(n)

code如下

 /*** 根据值,找到对应的节点* 从头节点 开始遍历** @param data* @return*public ArtisanNode find(Object data) {// 头节点的临时变量,直接用head就把head给改变了,不可取。ArtisanNode currentNode = head;// 遍历while (currentNode != null) {if (currentNode.data == data) { // 如果匹配,终止循环break;} else {currentNode = currentNode.next; // 不匹配则将下个节点赋值给当前节点,继续循环}}System.out.println("当前节点:" + currentNode.toString());return currentNode;}

单向链表的插入

插入的话 分为三种场景,头插、尾插、中间插入


头插

头插就是插入头部节点。 流程如下


尾部插入

尾插就是插入尾部节点。 流程如下


中间插入


单向链表的删除


删除头节点


删除中间的节点


删除尾部节点


Code


/*** @author 小工匠* @version v1.0* @create 2020-01-01 07:36* @motto show me the code ,change the word* @blog https://artisan.blog.csdn.net/* @description**/public class ArtisanSingleLinkedList {// 头节点private ArtisanNode head;// 单向链表的长度private int size;/*** 构造函数*/public ArtisanSingleLinkedList() {this.size = 0; // 初始化长度为0this.head = null;// 初始化head为null}/*** 头插** @param data*/public void add2Head(Object data) {ArtisanNode node = new ArtisanNode(data); // 初始化一个Nodenode.next = head;// 将这个新Node的next指向headthis.head = node;// 把这个新的node置为headsize++;  // 更新链表容量}/*** 尾插** @param data*/public void add2Tail(Object data) {ArtisanNode node = new ArtisanNode(data);ArtisanNode currentNode = head;while (currentNode != null){ // 遍历if (currentNode.next == null){ // next为null,说明到了tailcurrentNode.next = node; // 将next节点指向新增节点break; // 跳出循环}else {currentNode = currentNode.next; // 不匹配则将下个节点赋值给当前节点,继续循环}}size++;}/*** 插入链表的中间 假设在第N个位置插入** @param data*/public ArtisanNode add2Nth(Object data, int position) {ArtisanNode node = new ArtisanNode(data);if (position == 0) { // 如果position = 0 ,头插add2Head(data);} else { // 找到对应的位置// 头节点的临时变量,直接用head就把head给改变了,不可取。ArtisanNode currentNode = head;for (int i = 1; i < position; i++) {currentNode = currentNode.next; // 一直往后遍历}node.next = currentNode.next; // 当前节点的next节点 赋值给 新节点的nextcurrentNode.next = node; // 当前节点的next节点指向新节点}size++; // 更新链表容量return node;}/*** 根据值,找到对应的节点* 从头节点 开始遍历** @param data* @return*/public ArtisanNode find(Object data) {// 头节点的临时变量,直接用head就把head给改变了,不可取。ArtisanNode currentNode = head;// 遍历while (currentNode != null) {if (currentNode.data == data) { // 如果匹配,终止循环break;} else {currentNode = currentNode.next; // 不匹配则将下个节点赋值给当前节点,继续循环}}System.out.println("当前节点:" + currentNode.toString());return currentNode;}/*** @return 单向链表当前的容量*/public int getSize() {System.out.println("ArtisanSingleLinkedList 当前的容量为:" + size);return size;}/*** 删除头节点* 时间复杂度 O(1)*/public ArtisanNode deleteHead(){this.head = head.next ; // 将头节点的nextsize--;return head;// 返回头节点}/*** 删除指定位置的节点** 时间复杂度 O(n)*/public ArtisanNode deleteNth(int position){ArtisanNode currentNode = head;if (position == 0 ){deleteHead();}else{for (int i = 1; i < position; i++) {currentNode = currentNode.next;}currentNode.next = currentNode.next.next; //cur.next 表示的是删除的点,后一个next就是我们要指向的}size--;return currentNode.next; // 返回被移除的节点}/*** 删除尾部节点*/public ArtisanNode deleteTail(){ArtisanNode currentNode = head;ArtisanNode previosNode = head;while (currentNode != null){if (currentNode.next == null){previosNode.next = null;break;}else {previosNode = currentNode;currentNode = currentNode.next;}}size--;return previosNode; // 返回尾结点}public void print(){ArtisanNode currentNode = head;while(currentNode != null){System.out.print(currentNode.data+" -> ");// 从头节点开始输出currentNode = currentNode.next;}System.out.println();}public static void main(String[] args) {ArtisanSingleLinkedList single = new ArtisanSingleLinkedList();// 头插single.add2Head(5);single.add2Head(4);single.add2Head(3);single.add2Head(2);single.add2Head(1);single.getSize();single.print();// 查找数据single.find(4);// 指定位置插入single.add2Nth("InsertedData", 2);single.getSize();single.print();// 尾插single.add2Tail("小工匠");single.print();single.getSize();// 删除中间节点single.deleteNth(2);single.print();// 删除尾部节点single.deleteTail();single.getSize();single.print();}
}/*** Node节点*/
class ArtisanNode {Object data; // 数据域ArtisanNode next; // 指针域,指向下一个节点/*** 构造函数** @param data*/public ArtisanNode(Object data) {this.data = data;}@Overridepublic String toString() {return "ArtisanNode{" +"data=" + data +", next=" + next +'}';}
}


总结

  • 1. 说到数组就要想到下标,查找使用下标去查找,因为根据下标查找的时间复杂度为O(1).
    不要试图使用根据元素的值去查找,因为这样的话,根据值去查找,时间复杂度为O(n)

  • 2. 数组的话,需要考虑数组越界的问题, 合理的动态扩容/缩容 , 减少不必要的内存浪费

  • 3. CPU可以把数组缓存到CPU内部,执行效率比链表更高。 为啥可以缓存数组呢? ---->
    数组是在内存里连续的, 索引找到了首地址,其他元素也就都找到了。 链表在内存中 是没有规律的,通过指针项链,没发被CPU缓存。

  • 4. 说到链表,不需要考虑下标的问题,所以不能根据下边来查找,肯定是需要根据数据域存储的数据来查找,从头遍历,通过next执行,一直遍历下去,直到找到数据位置。所以时间复杂度为O(n)

  • 5. 链表 虽然查找慢,但是插入和删除快啊,动动指针即可,不用挪元素。时间复杂度O(1)

  • 6. 链表 因为本身支持动态扩容,所以一定要考虑 链表占用的内存大小。。。切记。

Algorithms_基础数据结构(02)_线性表之链表_单向链表相关推荐

  1. Algorithms_基础数据结构(04)_线性表之链表_单向循环链表约瑟夫环问题

    文章目录 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 约瑟夫问题 结构 分析 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 tip:单向链表 约瑟夫问题 N个人围成一圈, ...

  2. Algorithms_基础数据结构(03)_线性表之链表_双向链表

    文章目录 大纲图 双向链表 双向链表的基本结构 双向链表的基本操作 头插 尾插 中间部位插入 删除头部 删除尾部 删除中间位置的数据 查找 更新 Code 总结 大纲图 双向链表 Algorithms ...

  3. java实现线性表的案例_数据结构—线性表(LinearList)的原理以及Java实现案例

    线性表:零个或多个数据元素的有限序列.包括数组.链表.栈空间.队列等结构都属于线性表. 本文将介绍Java线性表中的数组.链表的实现逻辑,并附有数组线性表.单链表.静态链表的Java实现源码. 数据结 ...

  4. Java数据结构与算法_线性表_顺序表与链表

    文章目录 线性表 顺序表 顺序表API设计 顺序表的代码实现 链表 单向链表 双向链表 总结 线性表 概述 线性表是最基本.最简单.也是最常用的一种数据结构. 一个线性表是n个具有相同特性的数据元素的 ...

  5. c语言创造线性表储存复数,《c语言数结构》第02章 线性表.ppt

    <c语言数结构>第02章 线性表 第1章回顾 数据结构课程-- 数据结构+算法=程序,涉及数学.计算机硬件和软件. 数据结构定义--指互相有关联的数据元素的集合,可用data_Struct ...

  6. 算法实例_线性表 By:比方

    算法实例_线性表 By:比方 什么是线性表? 从线性表的功能逻辑上来看,线性表就是由n(n>=0)个数据元素的排序组合,数据由x1,x2,x3,...,xn结构有序的顺序排列. 线性表的结构和特 ...

  7. C语言数据结构-第二章线性表-电大

    第二章线性表--内容简介 本章将进入线性结构的学习. 线性结构是最简单.最常用的一种数据结构. 本章将学习线性表的定义.顺序和链式两种存储方式及相应存储结构上的运算实现.通过典型示例训练,掌握线性表的 ...

  8. 【数据结构】除去线性表中的重复数字

    题目:写一个算法将单链表中值重复的结点删除,使所得的结果表中各结点值均不相同. 刚看到这个题目给我第一个思路是冒泡排序,可以利用冒泡排序的两层循环找出相同的结点,然后free掉.第一层循环是控制循环的 ...

  9. 进栈顺序为abcd则出栈顺序为_线性表之顺序表示

    线性表 1. 线性表的基础知识 1.1 线性表的定义 线性表是具有相同数据类型的n(n>0)个数据元素的有限序列. 若用L命名,表示:L=(a1,a2,a3,-,ai-1,ai,ai+1,-,a ...

最新文章

  1. linux之sed命令的用法
  2. ANDROID STUDIO 2.2 来啦
  3. 【实用】ALV 清单右击隐藏列失效的处理
  4. [Step By Step]SAP HANA PAL指数回归预测分析Exponential Regression编程实例EXPREGRESSION(模型)...
  5. date(w) 输出后对应的周几不对的问题
  6. 顺序表应用5:有序顺序表归并
  7. 生物学专业_江南大学微生物学(发酵)20002008历年考研专业课真题汇编
  8. 帝国CMS7.2仿极客网互联网自媒体门户模板
  9. 吴恩达机器学习学习笔记第七章:逻辑回归
  10. 设计模式_01单例模式
  11. 可见的轮廓线用虚线绘制_CAD制图初学入门教程:CAD软件中如何绘制轴测图?
  12. Mac安装Anaconda
  13. matlab读取trmm,基于Matlab的TRMM3B43数据处理的思维过程与技术流程
  14. win10计算机停止工作,Win10系统总提示Rundll32已停止工作的解决方法
  15. 树莓派 与 Xbox360手柄 基于pygame 的一次邂逅
  16. 南航里程每年清空吗_速度用!南航里程即将大量贬值!还有每年3张南航处卡!...
  17. go语言 Golang官网被墙解决办法
  18. 爬虫代理和验证码识别
  19. 传说之下计算机音乐大全,传说之下同人音乐
  20. [DB][Oracle]Oracle格式化数字的方法(指定小数点位数,每3位加逗号)

热门文章

  1. html tr中可以有br吗,html table tr td br 什么意思 缩写
  2. ping 超时时间_华为交换机ping命令详解
  3. C++:读写二进制文件到double数组
  4. python sin(x)/x 图像
  5. keras实现 vgg16
  6. 表白编程代码python_python抖音表白程序源代码
  7. MATLAB从入门到精通-APP调用simulink中的参数,并且修改,将结果返回到APP中
  8. MATLAB三维曲面绘图你不得不知道的...
  9. MATLAB实战系列(十一)-多种群遗传算法的函数优化算法(附MATLAB代码)
  10. reactor线程模型_简单了解Java Netty Reactor三种线程模型