数据结构学习笔记(0X01)--数组

一、前言:为什么大部分编程语言的数组都是从0开始编码?

  1. 从数组存储的内存模型上来看,“下标”确切的说法就是一种“偏移”,相比从1开始编号,从0开始编号会少一次减法运算,数组作为非常基础的数组结构,通过下标随机访问元素又是非常基础的操作,效率的优化就要尽可能的做到极致。

    数组下标从0开始计数,a[k]的内存地址公式为:a[k]_address = base_address + k * type_size

    数组下标从1开始计数,a[k]的内存地址公式为:a[k]_address = base_address + (k-1)*type_size

    对比两个公式,我们发现,从1开始编号,每次随机访问数组元素都多了一次减法运算,对于cpu来说,就是多了一次减法指令。

  2. 主要的原因是历史原因,C语言的设计者是从0开始计数数组下标的,之后的Java、JS等语言都进行了效仿,或者说是为了减少从C转向Java、JS等的学习成本。

二、什么是数组?

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

数组的精髓:线性表、连续的内存空间和相同类型的数据。

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

    非线性表:比如二叉树、堆、图等,在非线性表中,数据之间并不是简单的前后关系。

  2. 关键字:连续的内存空间和相同类型的数据。数组支持随机访问,根据下标随机访问的时间复杂度为O(1)

    优点:两限制使得具有随机访问的特性
    缺点:删除,插入数据效率低

    为何数组插入和删除低效

    插入:
    若有一元素想往int[n]的第k个位置插入数据,需要在k-n的位置往后移。
    最好情况时间复杂度 O(1)
    最坏情况复杂度为O(n)
    平均负责度为O(n)

    如果数组中的数据不是有序的,也就是无规律的情况下,可以直接把第k个位置上的数据移到最后,然后将插入的数据直接放在第k个位置上。

    这样时间复杂度就将为 O(1)了。

    删除:
    与插入类似,为了保持内存的连续性。
    最好情况时间复杂度 O(1)
    最坏情况复杂度为O(n)
    平均负责度为O(n)

    提高效率:将多次删除操作中集中在一起执行,可以先记录已经删除的数据,但是不进行数据迁移,而仅仅是记录,当发现没有更多空间存储时,再执行真正的删除操作。这也是 JVM 标记清除垃圾回收算法的核心思想。

    数组访问越界问题
    C语言中的数据越界是一种未决行为,一般比较难发现的逻辑错误。相比之下,Java会有越界检查。

三、数组与链表的区别

  1. 数组中的元素存在一个连续的内存空间中,而链表中的元素可以不存在于连续的内存空间。
  2. 数组支持随机访问,根据下标随机访问的时间复杂度是O(1)

四、数组内存寻址方式

一维数组:a[i]address=base_address+itype_size
二维数组:二维数组假设是mn, aiaddress=base_address + (in+j)type_size
三维数组:三维数组假设是mnq, ai[k]_address=base_address + (inq + jq + k)type_size

你可能感兴趣的:(数据结构和算法)