数组和链表

2019-05-26  本文已影响0人  麦兜的夏天

数组

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

(1)数组适合查找操作,但是要说查找的时间复杂度是 O(1),是不严谨的。比如排好序的数组,使用二分查找的时间复杂度为 O(logn)。严谨的说法是,根据下标随机访问的时间复杂度为 O(1)。

根据下标随机访问高效的原因:
因为数组的内存空间是连续的,并且每个元素占用的内存大小相同(数据类型相同),所以通过公式很容易计算出指定元素的地址。

a[i]_address = base_address + i * data_type_size

a[i]_address : i 号元素的内存地址
base_address : 内存块的首地址
data_type_size : 数组中每个元素的大小。例:int 类型,就是4字节

(2)增删操作效率低的改进办法:

(3)容器能否完全代替数组?


链表

链表与数组的区别是,它不像数组那样使用连续的内存空间,而是通过“指针”将一组零散的内存块串联起来。

常见的链表有:单链表、双向链表和循环链表等。

一、

(1)单链表 单链表.png

链表中,每个蓝色快被叫做节点,Next 叫做指针。

(2)循环链表

它是一种特殊的单链表。只是将结尾节点的指针指向头节点。 image.png 当要处理的数据具有环形特征的时候,就采用循环链表。比如著名的约瑟夫问题。
(3)双向链表 image.png 双向链表额外的两个空间用来存储后继节点和前驱节点的地址。因此它不像单链表那样只支持单项遍历,它可以支持双向遍历。

二、链表与数组相比的优缺点:

(1)单链表和双向链表在增删操作的时候时间复杂度不一样在什么地方?
以删除操作为例。
实际开发中,从链表中删除一个数据无外乎有两种情况:

1.删除节点中“值等于某个给定值”的节点
2.删除某一指针指向的节点

这也是实际开发中,双向链表尽管很费内存,但却应用更加广泛的原因。java 中的 LinkedHashMap 就用到了双链表数据结构。这就是用空间换时间的设计思想。

(2)链表 VS 数组性能大比拼


image.png

不过数组与链表的对比,并不能局限于时间复杂度。

数据使用的是连续的内存空间,可以借助 CPU 的缓存机制,预读数组中的数据,所以访问效率更高。而链表在内存中并不是连续存储的,所以对 CPU 的缓存不友好,无法预读。

数组的缺点是大小固定,一经生命就要占用整块连续内存空间。如果生命的数组过大,可能会导致内存不足“out of memory”,而如果申请的数组过小,内可能出现不够用的情况,这时再去申请内存空间,又牵扯到数据搬移的问题,比较费时。链表则天然的支持动态扩容。

此外,如果代码对内存的要求比较苛刻,那么数组更加合适。因为链表的每个节点都需要额外的空间去存储下个节点的指针,所以内存消耗会翻倍。而且,对链表进行频繁的插入、删除操作,可能会导致频繁的内存申请和释放,Java 语言中可能会导致频繁的 GC。

上一篇下一篇

猜你喜欢

热点阅读