数组是什么?
数组是有限个相同类型的变量所组成的有序集合。它在内存中顺序存储。
在python中,并没有直接使用数组这个概念。而是使用列表和元组这两种集合,本质上都是对数组的封装。列表是一个动态可扩展的数组,支持任意地添加、删除、修改元素。元组是一个不可变的集合,一旦创建就不在支持修改。
数组的基本操作
1、读取元素 根据数组下标进行读取
list = [1,2,3,4,5]
print(list[2])
2、更新元素
list[3] = 10
print(list[3])
数组读取和更新的时间复杂度都是O(1)
3、插入元素 时间复杂度是O(n)
- 尾部插入 直接把插入的元素放在数组尾部的空闲位置即可 list.append(6)
- 中间插入 list.insert(5,10)
- 超范围插入 需要创建一个新数组实现数组的扩容
4、删除元素 与插入操作的过程相反 时间复杂度是O(n)
链表是什么?
链表(linked list)是一种在物理上非连续的、非顺序的数据结构,由若干节点所组成。
单向链表的每一个节点包含两部分。存放数据的变量data和指向下一个节点的指针next。
第一个节点称为头节点,最后一个节点称为尾节点。尾节点的next指针指向空。
通过链表的一个节点,那你如何快速找到它的前一个节点呢?
双向链表
双向链表相比单向链表,会多一个指向前置节点的prev指针
那链表在内存中是如何存储的呢?
随机存储
什么叫随机存储呢?
链表采用的是见缝插针的方式,它的每一个节点分布在内存中的不同位置,依靠next指针进行关联。
这样有哪些好处呢?
这样可以灵活有效地利用零散的碎片空间
链表的基本操作
1、查找节点
查找节点时,只能从头节点开始向后逐一查找 。即链表中的数据只能按顺序进行访问,最坏的时间复杂度是O(n)
2、更新节点
直接替换即可
3、插入节点 只要内存空间允许,插入链表的元素是无穷无尽的,不需要考虑扩容的问题。
- 尾部插入 最后一个节点的next指针指向新插入的节点即可
- 头部插入
- 新节点的next指针指向原先的头节点
- 把新节点变成链表的头节点
- 中间插入
- 新节点的next指针指向插入位置的节点
- 插入位置前置节点的next指针,指向新节点
4、删除节点 只要内存空间允许,插入链表的元素是无穷无尽的,不需要考虑扩容的问题
- 尾部删除 倒数第二个节点的next指针指向空即可
- 头部删除 将头节点设置为原先的头节点的next指针所指向的节点即可
- 中间删除 删除节点的前置节点的next指针指向删除元素的下一个节点即可
我们不用刻意去释放被删除的节点,只要没有外部引用指向它们,被删除的节点会被自动回收
不考虑插入、删除操作之前的查找元素的过程,只考虑纯粹的插入和删除操作,时间复杂度都是O(1)
数组和链表相关操作的性能:
查找 | 更新 | 插入 | 删除 | |
数组 | O(1) | O(1) | O(n) | O(n) |
链表 | O(n) | O(1) | O(1) | O(1) |
总结:
数组和链表都属于线性数据结构。数据结构没有绝对的好与坏,数组和链表各有优劣。数组的优势在于可以快速定位元素,适合读多写少的场景。链表的优势在于能够灵活地进行插入和删除操作。