本文经授权转载自微信公众号:小争哥(xiaozhengge0822),作者:小争哥

数组和链表作为最基础的数据结构,在面试的时候,经常会被问到。最常被问到的一个问题,那就是,对比一下数组和链表。如果你是Java工程师,会被问到可能就是对比一下ArrayList和LinkedList。

从我面试的经历来看,最常听到的答案就是:数组查找的时间复杂度是O(1),但是删除、插入数据的时间复杂度是O(n);而链表查找的时间复杂度是O(n),但是删除、插入数据的时间复杂度是O(1)。

当然,这样的答案并不全错,但是过于笼统,过于教科书。为什么我会这么说呢?

这里有几点回答不准确的地方,我一一纠正一下。

1. "数组查找的时间复杂度是O(1)"--描述不准确

实际上,在数组中查找一个数据,并不快速。打个比方,如果我们数组中存储的是10个整数,2、3、1、19、...、12,如果我们要在里面查找数据12,我们还是要一个一个的遍历整个数组元素,所以时间复杂度仍然是O(n)。即便数组中存储的数据是有序的,我们利用二分查找算法来查找,那时间复杂度也只能做到O(logn)。

也就是说,在数组中,按照元素的值来查找,时间复杂度并不是O(1)。所以,“数组查找的时间复杂度是O(1)”表述是不对的。那正确是表述应该是怎样的呢?

正确的表述应该是:“数组中按照下标随机访问的时间复杂度是O(1)”。这也是数组这种数据结构最大的特点之一了。如果在面试中,你能如此回答,面试官肯定会对你刮目相看。

2. “链表删除数据的时间复杂度是O(1)”--描述不准确

实际上,这句话也不是全错,主要还是描述不够准确。链表的删除操作可以分为好几种情况,我们现在列出三种,将其定义为三个删除函数。

void remove(Node* list, int dataValueToBeDeleted);
void remove(Node* list, Node *pNodeToBeDeleted);
void remove(Node* list, Node* pPreviousNodeToBeDeleted);

我们逐一来看下,每个不同的删除方式,时间复杂度都是多少。

1)第一种删除方式:void remove(Node* list, int dataValueToBeDeleted);

其中,list表示链表,dataValueToBeDeleted参数表示要删除的元素的值。比如,链表中存储了5个数据,分别是:4、7、9、1、3,当dataValueToBeDeleted=9的时候,表示删除链表中值等于9的那个结点。

对于这种删除方式来说,我们总是要从链表头开始遍历整个链表数据,才能找到存储了数据9的那个结点,所以,遍历链表操作的时间复杂度是O(n)。

当通过遍历找到这个要删除的结点的时候,我们删除它就很快速了,因为在遍历的过程中,我们可以事先记录要删除结点的前驱结点。有了前驱结点,我们只需要简单的指针操作,就可以将要删除的结点删除。这一步操作的时间复杂度是O(1)。

所以,根据大O时间复杂度表示法中的加法法则,这种删除操作的总的时间复杂度是O(n)。

2)第二种删除方式:void remove(Node* list, Node *pNodeToBeDeleted);

这种删除方式中,list仍然表示链表,而我们pNodeToBeDeleted表示要删除的结点的指针,反过来说,也就是,我们要删除pNodeToBeDeleted这个指针指向的结点。

对于这种删除方式,我们也要分两种情况来考虑。

如果list链表是单链表,那这种删除方式的时间复杂度是O(n)。因为,我们要删除pNodeToBeDeleted结点,就要先找到它的前驱结点。而在单链表中,查找一个结点的前驱结点的时间复杂度是O(n)。所以,对于单链表来说,这种删除操作的时间复杂度是O(n)。

如果list链表是双向链表,那这种删除方式的时间复杂度是O(1)。因为,在双向链表中,我们可以快速地得到pNodeToBeDeleted结点的前驱结点,时间复杂度是O(1)。

3)第三种删除方式:void remove(Node* list, Node* pPreviousNodeToBeDeleted);

这种删除方式表示,我们删除pPreviousNodeToBeDeleted指针指向的下一个结点。这里注意,并不是要删除pPreviousNodeToBeDeleted指针指向的结点。

因为我们已经拿到了要删除结点的前驱结点,所以,不管是单链表还是双向链表,对于这种删除方式,时间复杂度都是O(1)。

3. “链表插入数据的时间复杂度是O(1)”--描述不准确

对于插入的情况,跟删除情况类似,也是描述不够准确。在链表中插入数据,有很多种情况。比如,我们定义的下面这几个函数表示的情况。

void insertBefore(Node* p, int dataValue);
void insertAfter(Node* p, int dataValue);

第一个函数表示,在p节点前面插入一个结点,结点值为dataValue。对于单链表来说,这种插入操作的时间复杂度是O(n)。对于双向链表来说,这种插入操作的时间复杂度是O(1)。这里我只给出结论,具体留给你自己来分析吧。

第二个函数表示,在p节点后面插入一个结点,结点值为dataValue。不管是单链表还是双向链表,这种插入操作的时间复杂度都是O(1)的。

当然,还有跟多的插入方式,比如下面这两种,时间复杂度又是不一样的。

void insertAtHead(Node* listHead, int dataValue);
void insertToTail(Node* listHead, int dataValue);

总结一下,也就是说,在分析链表和数组上操作的区别的时候,一定要描述准确各个操作是如何定义的,这样才好具体分析时间复杂度。同样的操作,不同的定义方式,时间复杂度是不一样的

有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

好文章,我在看❤️

从链表中删除数据的时间复杂度真的是O(1)吗?相关推荐

  1. namenode的元数据会被删除吗_从链表中删除数据的时间复杂度真的是O(1)吗?

    本文转载自微信:小争哥(xiaozhengge0822),作者:小争哥 数组和链表作为最基础的数据结构,在面试的时候,经常会被问到.最常被问到的一个问题,那就是,对比一下数组和链表.如果你是Java工 ...

  2. python链表中删除一个节点数据_python实现单链表中删除倒数第K个节点的方法

    本文实例为大家分享了python实现单链表中删除倒数第K个节点的具体代码,供大家参考,具体内容如下 题目: 给定一个链表,删除其中倒数第k个节点. 代码: class LinkedListAlgori ...

  3. 从无头单链表中删除节点 结构之法 4

    题目: 假设有一个没有头指针的单链表.一个指针指向此单链表中间的一个节点(不是第一个,也不是最后一个节点),请将该节点从单链表中删除. 分析与解答: 假设给定的指针为pCurrent,Node *pN ...

  4. 在DataList控件中删除数据记录

    (一)在DataList控件中删除记录的设计要点 在DataList控件中删除数据记录的设计相对简单一点.该功能设计的重点在于当用户单击[删除]按钮时,程序如何判断要删除的是哪一行.使DataList ...

  5. 无头结点单链表的逆置_从无头单链表中删除节点及单链表的逆置

    题目: 假设有一个没有头指针的单链表.一个指针指向此单链表中间的一个节点(非第一个节点, 也非最后一个节点).请将该节点从单链表中删除. 解答: 典型的"狸猫换太子", 若要删除该 ...

  6. 我可以从iOS DeviceSupport中删除数据吗?

    本文翻译自:Can I delete data from iOS DeviceSupport? After going through and cleaning my disk with old th ...

  7. 《程序员代码面试指南》第二章 链表问题 在单链表和双链表中删除倒数第K个节点...

    题目 在单链表和双链表中删除倒数第K个节点 java代码 /*** @Description:在单链表和双链表中删除倒数第K个节点* @Author: lizhouwei* @CreateDate: ...

  8. 编程之美-从无头单链表中删除节点方法整理

    [试题描述] 假设有一个没有头指针的单链表.一个指针指向此单链表中间的一个节点(不是第一个,也不是最后一个),请将该节点从单链表中删除. 程序:

  9. C语言从已排序的链表中删除重复项(附完整源码)

    C语言从已排序的链表中删除重复项 C语言从已排序的链表中删除重复项完整源码(定义,实现,main函数测试) C语言从已排序的链表中删除重复项完整源码(定义,实现,main函数测试) #include ...

最新文章

  1. Leetcode 268. 缺失数字 解题思路及C++实现
  2. VC资源分配、释放表
  3. 【pytorch】torch 查看GPU
  4. BugKuCTF 加密 散乱的密文
  5. Java有序表查找:折半查找、二分查找、差值查找和斐波那契查找
  6. localStorage使用总结
  7. Disruptor并发框架--学习笔记
  8. 帮助推动Java EE向前发展
  9. VSCode 调试 Egg 完美版 - 进化史 #25
  10. JavaScript学习(三十一)—在输入框中如何判断输入的是一个正确的网址
  11. 未来语音识别技术的发展趋势将会怎样
  12. centos7上mycat安装_Mysql+Mycat实现数据库主从同步与读写分离
  13. c语言算除法会把小数转成整数,在C语言中除法运算为什么没有小数部分?
  14. 网页视频html转换ppt,ppt转web ppt可以转换为视频文件?
  15. RS485串口通信实验
  16. 圣安地列斯服务器没有响应,Windows10系统玩不了侠盗猎车圣安地列斯怎么办?解决方案...
  17. linux下通过inode删除文件
  18. 物联网卡设置_移动、联通、电信物联网卡APN设置教程
  19. 剑指Offer-22反转链表
  20. 一对一语音直播系统源码——如何解决音视频直播技术难点

热门文章

  1. 铁幕一体计算机配置,讽刺的铁幕来自俄罗斯套娃的爱情配置要求介绍 配置要求高吗_游侠网...
  2. php里isset的属性,PHP魔术方法__isset()
  3. mysql性能仪表盘_mysql-笔记-性能
  4. 表格 大小_单元格大小乱七八糟?给我3秒,还你一个完美表格!
  5. java httpclient 异步请求_Java利用httpasyncclient进行异步HTTP请求
  6. 在Windows 下使用CodeBlocks 自带编译器实现对编译的优化
  7. 九度OJ : 1004 Median
  8. 计组之数据运算:12、加法器设计
  9. (操作系统题目题型总结)第三章:同步与互斥
  10. Linux系统编程23:基础IO之了解硬盘物理和逻辑结构及明白inode的本质和掌握软硬链接及其区别