数组
数组定义:是有序的元素序列,若将有限个类型相同的变量的集合命名,那么这个名称为数组。
java中初始化一个int类型数组int[] temp=new int[8];表示初始化一个数组里面都放int类型的值,数组长度是8。
数组是一组有序的元素的集合,那么在内存分配上,数组必须先分配一段连续的内存地址。你想象成数组就像一个连续从0标号的的台阶。
你要知道哪个台阶上放的东西,你只需要知道这个台阶的下标号,直接去这个标号的台阶上取东西就行了。
你不需要知道其他台阶上的标号和东西,也不用从第一个台阶往上依次找。
数组之间是通过下标维护的,数组支持随机查找。
比如你要找index是7的值,只需要通过数组的下标找到index是7就能找到对应的值。
如图下标是7的值是90,那么就是temp[7]=90;所以数组的查询速度很快是O(1)的时间复杂度。
说完查找,那么数组的新增和修改是怎么样的呢?
你现在有个需求需要在楼梯index是2和3的地方加一层台阶,你怎么办?
那么只有把index是3以后的台阶都往后挪动一位,将原来长度是8的台阶变成长度是9的台阶。
如图红色的是加的index为3的台阶,后面颜色变深的是index:3,4,5,6,7的台阶index+1向后移动一位的结果变成index:4,5,6,7,8的台阶。
台阶的内容不变,红色前面的是index是3的值之前index:1,2的台阶和之前一样index和值没有任何变化。
最坏的结果在数组最前面加一层台阶整个台阶(数组)都要往后移动一阶,时间复杂度是O(n)。
最好的情况是在数组最后加一阶那么直接将数组长度+1,时间复杂度是O(1)。那么总的来说数组的新增修改需要移动数组效率较低。
数组删除元素,如果你现在需要把上面3加的index值是3的台阶删掉。
那么需要将index是3之后的index和值往前移动一位,就是将index是:4,5,6,7,8的值-1变成:3,4,5,6,7。
如图:和新增一样最坏的情况是删除第一个index是1的值,index为1的值之后的所有元素都要往前移动一位,时间复杂度O(n)。
最好的情况删除最后一个元素不用移动数组,时间复杂度O(1)。
数组如果申请的空间长度不够,扩展的时候会重新申请一段连续的内存空间不利于扩展。
链表
链表:是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
图示的是单链表,现只讨论单链表的数据结构。
那么链表在内存的分配上是怎样的呢,数组是连续的内存,那么链表申请内存的时候就不需要预先申请连续的内存。
链表在内存分配上链表物理地址就不连续,那么在两个不连续的物理内存存储的链表的内容通过next指针连接成一条链依次去查找。
有点按图索骥的意思。
就好像一个猜纸条的游戏,你拿到第一个纸条,需要打开看到这个纸条给你留的下个纸条的地址在哪。
你才能根据第一个纸条内容找到第二个纸条。
如果要找到第三个纸条,你必须依次打开第一个纸条找到第二个纸条,再根据第二个纸条的提示找到第三个纸条。
你不能随机的一下找到第三个纸条,那么查找的效率上链表效率低,最坏的情况从头找到尾时间复杂度是O(n)。
链表新增,数组的新增需要移动元素位置,那么链表如果需要新增怎么办?
是不是需要移动元素的位置?
回答:不需要移动位置,只需要改变这个你加入的位置的前面指针的指向,让前面的指针指向你新加的元素。
让新加的元素指向原指向你指针的下一个元素。只需要改变指针的指向,不需要移动元素效率高,时间复杂度O(1)。
原链表:
新增元素
链表删除,链表的删除只需要把上文指向新加的节点的指针变成指向原节点就好,时间复杂度O(1)。如图正好和新增相反的过程。
原链表
删除元素
总结
数组:查询效率高,新增和修改需要移动元素效率低,内存分配是连续的内存,扩容需要重新分配内存。
链表:新增和修改效率高,只需要修改指针指向就好。链表查询效率低,需要从链表头依次查找。内存分配不需要连续的内存,占用连续内存少。