什么是数据结构
- 数据项:一个数据元素可以由若干数据项组成
- 数据元素:是组成数据的、有一定意义的基本单位,在计算机中通常作为整体处理
- 数据对象:有相同性质的数据元素的集合,是数据的子集
- 数据结构:是相互之间存在一种或多种特定关系的数据元素的集合
person{// 数据元素
String name="李四" //数据项
String sex=“男”
}
ArrayList<person>
//多个person的集合:数据对象
// 以一定的关系存在:数据结构
数据结构
数组
在计算机中空间连续,按照申请的顺序存储,申请的空间大小一定.
- 优点:查询快,删除添加比较慢(因为数据移动,但是从尾部删除,相对速度会比较快): 因为索引内存连续
- 缺点:插入效率低,删除效率低,长度固定
- Android中使用:ArrayList
线性表
逻辑结构, 就是对外暴露数据之间的关系,不关心底层如何实现,可以数组实现或者链表实现
顺序表
顺序存储结构,多为数组实现
- 优缺点:插入效率低,删除效率低,长度固定
- Android 中使用:ArrayList
- 相关问题:
- ArrayList的大小是如何自动增加的?目标问题
- arrayList的遍历方法?: for 循环,for 循环增强器,迭代器三种
链表
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的 数据元素,这组存储单元(存储器的基本单位)可以是连续的,也可以是不连续的
单向链表
向一个方向指引的链表
Node{
object data;
Next next;
}
- 优点:随意进行增删改,插入效率高,删除效率高 ,长度可以随意修改: 内存空间不用连续,操作只是节点指引
- 缺点:内存不连续,不能随机查找
- Android 中使用:HashMap.entry
双向链表
双向指引的链表
- 优点:随意进行增删改,插入效率高,删除效率高,长度可以随意修改,当有序试查找效率比单链表快一倍 : 双链表双向指引,可以用二分查找法等去查找
- 缺点:内存不连续,不能随机查找
- Android 中使用 linkList,lruList
Node{
object data;
Node<OBJECT> PRO
Node<OBJECT> NEXT
}
队列
它是一种运算受限的线性表。 其限制是仅允许在表的一端进行插入和另一端取数据。 插入数据的一端是队尾,取数据的一端则是队头
基本队列
直线队列,
- 优点:解耦、异步、削峰
- 系统可用性降低,出现假的溢出,及队尾已经满了,队头还没放置数据
- Android 中使用:线程池
循环队列:
把队列的这种头尾相连的存储结构被称为循环队列,并且把一个空位置放置队尾,
- 优点:解耦、异步、削峰,避免假的溢出,
- 缺点:如果在队首出栈的话,无法通过front==rear 队列是否为空
- Android 中使用:线程池
队列扩展:
- 链式队列:队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已
- 双端队列:一种具有队列和栈的性质的数据结构。双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行
- 优先级队列:优先级队列和通常的栈和队列一样,只不过里面的每一个元素都有一个”优先级”,使用单列表,在处理的时候,首先处理优先级最高的。如果两个元素具有相同的优先级,则按照他们插入到队列中的先后顺序处理。
队列应用线程池:
栈
栈(stack)又名后进先出表,它是一种运算受限的线性表。 其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。
- 优点:解耦
- 缺点:栈的出栈顺序固定
- Android 中应用:Java 虚拟机栈
hash表
是由数组加链表组成的数据结构
- 优点:链表和数组的双重优点
- put(key,value)
- 先通过Hash算法 生成 hash
- 通过inDexFor 生成table 数组的dex 索引
- 找到index 索引位置后,添加node,如果通过相关算法后找到的是同一个index 造成hash 碰撞 4 hash碰撞后,生成多node 同一列表,添加到头部
- get(key)
- 先通过Hash算法 生成 hash
- 通过inDexFor 生成table 数组的dex 索引
- 通过索引找到链表
- 找到链表,遍历链表,node 保存着key,通过判断key,hash 是否相等来拿去node
-
Android 中使用:hashmap
-
jdk 1.8 之后当链表的长度大于阈值后用的是红黑数来替换链表,查询速度更快,
树
N个结点构成的有限集合
树中有一个称为”根(Root)”的特殊结点 其余结点可分为若干个互不相交的树,称为原来结点的”子树” 如 B-f
结点的度: 结点的子树个数
树的度:整个树子节点最多的数,如上图为三
叶结点:度为0的结点
父结点:有子树的结点是其子树的根结点的父结点
子结点: 若A是B的父结点,B就是A的子结点
结点的层次: 规定根结点在1层,子结点的层数是它父结点的层数加1
树的高度: 树中所有结点中最大的层次是这棵树的高度
- 优点:查询速度快,层次分明
- Android 中使用: Tree
二叉树
度为2的树(树中所有结点中最大的度), 子树有左右顺序之分
- 优点:查询速度快,层次分明
- Android 中使用: treeSet
二叉排序树
- 左子树的所有的值小于根节点的值
- 右子树的所有的值大于根节点的值
- 左、右子树满足以上两点
二叉平衡树
它是一 棵二叉排序树,它的左右两个子树的高度差(平衡因子)的绝对值不超过1,2. 平衡被打破,需要调整 并且左右两个子树都是一棵平衡二叉树。
目的:使得树的高度最低,因为树查找的效率决定于树的高度
如果A是一颗平衡二叉树,如果新插入一个元素,会有两个结果
- 平衡没有被打破,不用调整
- 平衡被打破,需要调整
调整原则:根据插入节点与失衡结点的位置关系来划分
- 插入节点在失衡结点的左子树的左边,只需要经过一次左旋即可达到平衡
LL旋转:
- 插入节点在失衡结点的右子树的右边只需要经过一次右旋即可达到平衡 RR旋转:
- 插入节点在失衡结点的左子树的右边,失衡结点的左子树先做RR旋转,失衡结点再做LL旋转也可达到平衡
LR旋转:
- 插入节点在失衡结点的右子树的左边,失衡结点的右子树先做LL旋转,失衡结点再做RR旋转也可达到平衡 RL旋转:
平衡树的应用:AVL
红黑树
它一种特殊的排序树,同时具备以下特征,
- 节点非红即黑
- 根节点是黑色
- 所有NUll节点称为叶子节点,且认为颜色为黑
- 所有红色节点的子节点都为黑色
- 从任一节点到其叶子节点的所有路径上都包含相同数目的黑节
目的:他的优点是插入调整复杂度度更低
红黑数的插入不同情况(因为插入节点的颜色如果为黑肯定破坏红黑树性质5,所以每次插入的点都是红结点,不管是变色还是旋转都是为看满足定义五条 )
- 插入的新节点N位于树的根上、插入的新节点的父节点是黑色(最理想的情况)
- 如果新节点的父节点(0008)和叔父节点(0017)都是红色节点,先插入新节点(红色),(变色)新节点的父节点、叔父节点、祖父节点都需要变色
- 如果新节点的父节点是红色同时叔父节点都是黑色,同时新节点是其父节点的左子节点而父节点又是其父节点的左子节点。我们进行一次右旋转调换新节点和其父节点的角色(以父节点为轴)
- 如果新节点的父节点是红色同时叔父节点都是黑色,同时新节点是其父节点的右子节点而父节点又是其父节点的右子节点。我们对祖父节点进行一次左旋转调换新节点和其父节点的角色(以父节点为轴)
- 如果新节点的父节点是红色同时叔父节点都是黑色,同时新节点是其父节点的右子节点而父节点又是其父节点的左子节点。我们进行一次左旋转调换新节点和其父节点的角色(第一次旋转),同时我发现节点(0008)符合情况3,再进行一次右旋转(第二次旋转)
- 如果新节点的父节点是红色同时叔父节点都是黑色,同时新节点是其父节点的左子节点而父节点又是其父节点的右子节点。我们进行一次右旋转调换新节点和其父节点的角色(第一次旋转),同时我发现节点(0017)符合情况4,再进行一次左旋转(第二次旋转)
Android 中使用:红黑树
哈夫曼树
构造一棵二叉树,该树的带权路径长度(有数值路径最短,)达到最小
每次把权值最小的两棵二叉树合并
左节点权值比右节点小
- 优点:空间使用最小,
- Android 中使用:Huffman,
B树
允许子节点可以有多个,优点是树会比较矮,查询速度更高;
B+ 树
B+树是B树的变种,拥有B树的优势。节点横向排序 ,扫库扫表的能力更强,索引效率更高。排序能力更强
Android 中使用:my sql
图
图由顶点(vertex)和边(edge)组成的一种结构。 顶点的集合V,边的集合是E,所以图记为G = (V,E)
- 图的权
- 图的度
- 图的数据结构
无向图
有向图
连通图
图的遍历
- 深度优先遍历
- :访问A。
- :A之后有去向“C,D,F”中的三条路。 随意选择一个----(A的邻接点)C。
- : C之后有去向“B,D”中的两条路。随意选择一个----(C的邻接点)B。
- :B已是尽头,无路可走(撞南墙)。于是回溯到上一步的C。
- : C之后去向“B”中的路已走过了。现在只有选择D。
- :D之后的路通向A,A已访问过。 于是回溯到C。
- :C的两条路都走过了,不通。 继续回溯到A。
- :A的(”C,D”)都走过了,不通。 只剩下F可走,走到F。
- :F有路(”G”)可走。 走到G。
A -> C -> B -> D -> F -> G -> E
- 广度图的使用
-
:访问A。
-
:访问上一步A的邻接点,有“C,D,F” 。依次访问C,D,F。
-
: 访问上一步( C,D,F )的邻接点,有B,G。
-
:访问上一步(B,G)的邻接点,有E。
-
: 访问上一步E的邻接点,没有了,结束。 。。。。。。
访问顺序是: A -> C -> D -> F -> B -> G -> E
Android 中使用::广度,深度
- 找出最短路径算法-Dijkstra算法
- 扫描AA邻接点,记录邻接点权重值
- 找出邻接点里最小的那个值
Android 中使用:Dijkstra
总结
在Android 开发中使用哪种数据结构, 看实际开发情况,时间复杂度和空间复杂度,二选一,没有百分百的使用场景,只有更适合!!!