数据结构与算法之美-03数组

本文详细介绍了数组这种线性表数据结构,强调了其连续内存空间和相同类型数据的特点,使得随机访问效率高。然而,插入和删除操作由于需要保持数据连续性,可能导致较高的时间复杂度。数组从0开始编号是为了优化寻址效率。讨论了数组操作的最佳和最坏情况,并提出了优化策略。
摘要由CSDN通过智能技术生成

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

线性表与非线性表

线性表:线性表就是数据排成像一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。除了数组,链表、队列、栈等也是线性表结构。

与线性表队里的概念是非线性表,比如二叉树、堆、图等。之所以叫非线性,是因为,在非线性表中,数据之间并不时间的前后关系。

连续的内存空间和相同类型的数据

正是因为有这两个限制,它才有了一个堪称“杀手锏”的特性:“随机访问”。

为了保持数据的连续性,数组的操作比如删除、插入操作都需要做大量的数据搬移工作。

根据下标随机访问数组元素

我们拿一个长度为10的数组来举例。let a = new Array(10).fill(' ')。如图,计算机给数组a[10],分配了一块连续内存空间 1000~1039,其中,内存块的首地址为 base_address = 1000。

计算机会给每个内存单元分配一个地址,计算机通过地址来访问内存中的数据。

// 计算机随机访问数据中的某个元素,首先通过寻址公式,计算出该元素存储的内存地址
a[i]_address = base_adress + i * data_type_size

在例中data_type_size就为4个字节。

数组查找的时间复杂度为O(logn),数组支持随机访问,根据下标随机访问的时间复杂度为O(1)

低效的“插入”和“删除”操作

1.插入元素

最好时间复杂度:数组末尾插入元素,这时时间复杂度为O(1)

最坏时间复杂度:开头插入元素,那么所有元素都要向后移动一位,时间复杂度为O(n)

平均情况时间复杂度为O(n)

如果数组是无序的,为了避免大规模数据搬移,可以将插入位置的原来的数据直接放到最后,利用这种技巧,在特定位置下,在某个位置插入元素的时间复杂度可以降为O(1)。

2.删除元素

最好时间复杂度:数组末尾删除元素,这时时间复杂度为O(1)

最坏时间复杂度:开头删除元素,那么所有元素都要向前移动一位,时间复杂度为O(n)

平均情况时间复杂度为O(n)

如果不追求连续性,将多次删除操作集中在一起执行。删除的效率将会提高很多。先记录下已经删除的数据。每次删除操作并不是真正的搬移数据,只是记录数据已经被删除。当数组没有更多空间存储数据时,再触发一次真正的删除操作,这样就大大减少了删除操作导致的数据搬移。

为什么大多数编程语言中,数组要从0开始编号,而不是从1开始呢?

从数组存储的内存模型上来看,“下标”最确切的定义应该是“偏移(offset)”。如果用a来表示数组的首地址,a[0]就是偏移为0的位置,也就是首地址。那么问题来了,如果数组的首地址从1开始,那么再访问数组中元素时,寻址公式就会变为

a[k]_address = base_address + (k-1) * base_adress

数组作为基础的数据结构,效率优化要尽可能做到极致,所以为了减少一次减法操作,数组选择了从 0 开始编号,而不是从1开始。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值