参考:《漫画算法-小灰的算法之旅》
目录
一、数组
1、数组的定义
数组是有限个相同类型的变量所组成的有序集合,数组中的每一个变量称为元素。数组是最简单、最常用的数据结构。
2、数组在内存中的存储方式
数组在内存中顺序存储,换句话说,就是数组中的每一个元素,都存储在小小的内存单元中,并且元素之间紧密排列,既不能打乱元素的存储顺序,也不能跳过某个存储单元进行存储。
在python中,没有数组这个概念,而是使用列表和元组这两种集合,其中,列表是一个动态可扩展的数组,而元组是一个不可变的结合。
3、数组的基本操作
(1)读取元素
(2)更新元素
(3)插入元素
-
尾部插入
直接把插入的元素放在数组尾部的空闲位置即可。
mylist.append(6)//尾部插入
-
中间插入
在中间插入时,需要将插入位置以及后面的元素向后移动一个位置,再将要插入的元素放到对应的插入位置:
mylist.insert(5,11)
-
超范围插入(数组扩容)
当数组已经填满元素,还想继续插入一个元素时,需要将数组扩容,数组扩容就是创建一个新数组,长度是旧数组的两倍,再把旧数组中的元素复制过去,如下图所示:
(4)删除元素
如果删除的元素在数组中间或者开头,需要将其后面的元素都向前挪动一位。
数组读取的时间复杂度为:O(1)
数组插入和删除的时间复杂度为:O(n)
4、数组的优势和劣势
优势:数组拥有非常高效的随机访问能力,只要给出下标,就可以用常量时间找到对应元素。
劣势:数组在插入和删除元素时,由于数组元素连续紧密地存储在内存中,插入、删除元素都会导致大量元素被迫移动,影响效率。
二、链表
1、链表的定义
链表是一种在物理上非连续、非顺序的数据结构,由若干节点组成。链表可以分为单向链表和双向链表。
2、单向链表
单向链表的每个节点包含两部分,一部分是存放数据的变量data,另一部分是指向下一个节点的指针next。如下图所示:
链表的第一个节点被称为头节点,最后一个节点称为尾节点,尾节点的next指针指向空。
链表随机寻找元素的方式:对于链表的其中一个 节点A,我们只能根据节点A的next指针来找出该节点的下一个节点B,再根据节点B的next指针找到下一个节点C.......
3、双向链表
双向链表除了有data和next两个指针外,还有指向前置节点的prev指针。如下图所示:
4、链表的基本操作
(1)查找节点
在查找元素示,链表只能从头节点开始向后一个一个节点逐个查找。
链表查找元素的时间复杂度为:O(n)。
(2)更新节点
如果不考虑查找节点的过程,链表的更新过程会像数组那样简单,直接把旧数据替换成新数据即可。
(3)插入节点
- 尾部插入
尾部插入就是把最后一个节点的next指针指向新插入的节点即可。
- 头部插入
先把新节点的next指针指向原先的头节点,再把新节点变为链表的表头。
- 中间插入
第一步,新节点的nex指针指向插入位置的节点;
第二步,插入位置前置节点的next指针,指向新节点。
5、删除元素
- 尾部删除
尾部删除,直接将倒数第二个节点的next指针指向空即可。
- 头部删除
头部删除,把链表的头节点设为原先头节点的next指针所 指向的节点即可。
- 中间删除
中间删除,把要删除节点的前置节点的next指针,指向要删除元素的下一个节点即可。
三、数组和链表的不同
1、数组在内存中的存储方式是顺序存储,在内存中的存储方式则是随机存储。具体说,数组在内存中占用了连续完整的存储空间,而链表的每一个元素分布在内存中的不同位置,依靠next指针进行关联,可以灵活有效地利用零散的碎片空间。如下图所示:
2、性能对比
查找 | 更新 | 插入 | 删除 | |
数组 | O(1) | O(1) | O(n) | O(n) |
链表 | O(n) | O(1) | O(1) | O(1) |