数组
- 数组是由相同类型的数据按顺序组成的一种引用数据类型
”按顺序组成“的理解:在连续的内存地址上排列
- 数组是一种有序可重复的数据结构
- 数组在内存中被分配以连续的内存空间进行存储
优点
- 按照索引查询元素速度快
- 按照索引遍历数组方便
缺点
- 数组的大小固定后,扩容、删除、添加操作,要创建新数组或移动元素,效率低
- 数组只能存储一种类型的数据
适用场景
- 频繁查询,
- 对存储空间要求不大
- 很少增加和删除的情况
链表
- 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
- 链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域
- 根据指针的指向,链表能形成不同的结构,例如单链表,双向链表,循环链表等
优点
- 不需要初始化容量
- 添加,删除很快,只需要改变前后两个元素结点的指针域指向地址即可
- 由于不用按顺序存储,链表在插入和的时候可以达到O(1)的复杂度
缺点
- 含有大量的指针域,占用空间较大
- 查找元素需要遍历链表来查找,非常耗时
适用场景:
- 频繁增删的情况
- 很少查询的情况
数组和链表插入删除操作的时间复杂度对比:
在只知道下标时
- 数组:O(n)需要移动其后所有项的位置
- 链表:O(n)需要遍历其前面所有项以得到下标对应的项
在拥有要操作的项的引用时
- 数组:O(n) 需要移动其后所有项的位置
- 链表:O(1) 无需遍历
就插入删除的执行函数来看的话,链表和数组在只知道下标的情况下,其时间复杂度都是O(n),性能上是不会有太大差别的。
因为数组不需要遍历,能直接取得要操作的对象,但是需要移动其后的所有项,而链表无法直接获取要操作的对象,需要遍历获取,之后直接删除或者插入,而不需要移动其他项。
为什么说链表的插入和删除比数组的性能好?
并不是说在任何情况下链表的插入和删除效率都要比数组的高,而是链表插入删除的最差时间复杂度也就是O(n)
而在已得到要操作的结点的引用时,它就能省去遍历的步骤直接插入删除,时间复杂度为O(1),
并且数组会有比如扩容等操作造成很多额外的时间支出,以及内存碎片所导致的空间支出。
栈
后进先出
使用LindedList实现
- put方法:list.addFirst()
- pop方法:list.removeFirst()
- peek方法:list.getFirst()
使用ArrayList实现
- put方法:arrayList.add()
- pop方法:arrayList.remove(arrayList.size() - 1)
- peek方法:arrayList.get(arrayList.size() - 1)
队列
先进先出
使用LindedList实现
- put方法:list.addLast()
- pop方法:list.removeFirst()
- peek方法:list.getFirst()
使用ArrayList实现
- put方法:arrayList.add()
- pop方法:arrayList.remove(0)
- peek方法:arrayList.get(0)
二叉树
- 一颗树至少会有一个节点
- 每个节点不能多于2个叶子
节点的定义:一个数据,两个指针
很容易想到递归,递归的出口就是当没有节点了,就返回
散列表
根据key和value直接进行访问的数据结构
堆
可以被看做一棵树的数组对象
-
堆中某个节点的值总是不大于或不小于其父节点的值;
-
堆总是一棵完全二叉树